diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 647511373cc31146c4f1ffae2c8522ca115a5dd2..53f370a9306262825663246b46cde74a05de6cba 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -5581,7 +5581,9 @@ dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "log",
  "pallet-balances",
+ "pallet-preimage",
  "pallet-scheduler",
  "parity-scale-codec",
  "scale-info",
@@ -5899,6 +5901,7 @@ dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "log",
  "pallet-balances",
  "parity-scale-codec",
  "scale-info",
@@ -6065,6 +6068,7 @@ dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "log",
  "pallet-balances",
  "parity-scale-codec",
  "scale-info",
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 4898312f9608f19ead8ae340204569fc8574d455..d10448cc2d183a1e944771b9e186fc849e7b266f 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -340,8 +340,6 @@ impl pallet_proxy::Config for Runtime {
 parameter_types! {
 	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
 		RuntimeBlockWeights::get().max_block;
-	// Retry a scheduled item every 10 blocks (1 minute) until the preimage exists.
-	pub const NoPreimagePostponement: Option<u32> = Some(10);
 }
 
 impl pallet_scheduler::Config for Runtime {
@@ -351,11 +349,10 @@ impl pallet_scheduler::Config for Runtime {
 	type RuntimeCall = RuntimeCall;
 	type MaximumWeight = MaximumSchedulerWeight;
 	type ScheduleOrigin = EnsureRoot<AccountId>;
-	type MaxScheduledPerBlock = ConstU32<50>;
+	type MaxScheduledPerBlock = ConstU32<512>;
 	type WeightInfo = pallet_scheduler::weights::SubstrateWeight<Runtime>;
 	type OriginPrivilegeCmp = EqualPrivilegeOnly;
-	type PreimageProvider = Preimage;
-	type NoPreimagePostponement = NoPreimagePostponement;
+	type Preimages = Preimage;
 }
 
 parameter_types! {
@@ -370,7 +367,6 @@ impl pallet_preimage::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type ManagerOrigin = EnsureRoot<AccountId>;
-	type MaxSize = PreimageMaxSize;
 	type BaseDeposit = PreimageBaseDeposit;
 	type ByteDeposit = PreimageByteDeposit;
 }
@@ -862,6 +858,7 @@ impl pallet_referenda::Config for Runtime {
 	type UndecidingTimeout = UndecidingTimeout;
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
+	type Preimages = Preimage;
 }
 
 impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
@@ -881,6 +878,7 @@ impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
 	type UndecidingTimeout = UndecidingTimeout;
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TracksInfo;
+	type Preimages = Preimage;
 }
 
 impl pallet_ranked_collective::Config for Runtime {
@@ -909,7 +907,6 @@ parameter_types! {
 }
 
 impl pallet_democracy::Config for Runtime {
-	type Proposal = RuntimeCall;
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type EnactmentPeriod = EnactmentPeriod;
@@ -949,14 +946,15 @@ impl pallet_democracy::Config for Runtime {
 	// only do it once and it lasts only for the cool-off period.
 	type VetoOrigin = pallet_collective::EnsureMember<AccountId, TechnicalCollective>;
 	type CooloffPeriod = CooloffPeriod;
-	type PreimageByteDeposit = PreimageByteDeposit;
-	type OperationalPreimageOrigin = pallet_collective::EnsureMember<AccountId, CouncilCollective>;
 	type Slash = Treasury;
 	type Scheduler = Scheduler;
 	type PalletsOrigin = OriginCaller;
 	type MaxVotes = ConstU32<100>;
 	type WeightInfo = pallet_democracy::weights::SubstrateWeight<Runtime>;
 	type MaxProposals = MaxProposals;
+	type Preimages = Preimage;
+	type MaxDeposits = ConstU32<100>;
+	type MaxBlacklisted = ConstU32<100>;
 }
 
 parameter_types! {
diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs
index b95940a2835ceb5d5f3b24b998d2508167ba8f4d..d947226f87fa066694f2a90f13deb749990b2534 100644
--- a/substrate/frame/bounties/src/lib.rs
+++ b/substrate/frame/bounties/src/lib.rs
@@ -819,7 +819,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		value: BalanceOf<T, I>,
 	) -> DispatchResult {
 		let bounded_description: BoundedVec<_, _> =
-			description.try_into().map_err(|()| Error::<T, I>::ReasonTooBig)?;
+			description.try_into().map_err(|_| Error::<T, I>::ReasonTooBig)?;
 		ensure!(value >= T::BountyValueMinimum::get(), Error::<T, I>::InvalidValue);
 
 		let index = Self::bounty_count();
diff --git a/substrate/frame/contracts/src/storage.rs b/substrate/frame/contracts/src/storage.rs
index c3fc0840d8649b509e4c164a909bd31bdd6509c7..cf10c3225c9202fe0db5def75e91994521ccd82d 100644
--- a/substrate/frame/contracts/src/storage.rs
+++ b/substrate/frame/contracts/src/storage.rs
@@ -340,7 +340,7 @@ where
 		let queue: Vec<DeletedContract> = (0..T::DeletionQueueDepth::get())
 			.map(|_| DeletedContract { trie_id: TrieId::default() })
 			.collect();
-		let bounded: BoundedVec<_, _> = queue.try_into().unwrap();
+		let bounded: BoundedVec<_, _> = queue.try_into().map_err(|_| ()).unwrap();
 		<DeletionQueue<T>>::put(bounded);
 	}
 }
diff --git a/substrate/frame/conviction-voting/src/lib.rs b/substrate/frame/conviction-voting/src/lib.rs
index 534941d6f7f66fd97f6e90d8b1a26e7b34104161..b876a9354ee59eab10e11479ecf913f432684a0c 100644
--- a/substrate/frame/conviction-voting/src/lib.rs
+++ b/substrate/frame/conviction-voting/src/lib.rs
@@ -400,7 +400,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 						Err(i) => {
 							votes
 								.try_insert(i, (poll_index, vote))
-								.map_err(|()| Error::<T, I>::MaxVotesReached)?;
+								.map_err(|_| Error::<T, I>::MaxVotesReached)?;
 						},
 					}
 					// Shouldn't be possible to fail, but we handle it gracefully.
diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml
index f0ab3162c892b630887f0c470fd6ba4c0ab5ce40..e50d39ff769026eb5c626022cf460231a9143262 100644
--- a/substrate/frame/democracy/Cargo.toml
+++ b/substrate/frame/democracy/Cargo.toml
@@ -24,11 +24,13 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys
 sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
 sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
 sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
+sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
+log = { version = "0.4.17", default-features = false }
 
 [dev-dependencies]
 pallet-balances = { version = "4.0.0-dev", path = "../balances" }
 pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" }
-sp-core = { version = "6.0.0", path = "../../primitives/core" }
+pallet-preimage = { version = "4.0.0-dev", path = "../preimage" }
 
 [features]
 default = ["std"]
@@ -42,6 +44,7 @@ std = [
 	"sp-io/std",
 	"sp-runtime/std",
 	"sp-std/std",
+	"sp-core/std",
 ]
 runtime-benchmarks = [
 	"frame-benchmarking/runtime-benchmarks",
@@ -49,4 +52,4 @@ runtime-benchmarks = [
 	"frame-system/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 ]
-try-runtime = ["frame-support/try-runtime"]
+try-runtime = ["frame-support/try-runtime",]
diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs
index ab7ee3331e319ccf4be3f60c785f88864e1bb0ec..424192e2521da69e81daa48f952d7a9cc54d4f7c 100644
--- a/substrate/frame/democracy/src/benchmarking.rs
+++ b/substrate/frame/democracy/src/benchmarking.rs
@@ -22,24 +22,16 @@ use super::*;
 use frame_benchmarking::{account, benchmarks, whitelist_account};
 use frame_support::{
 	assert_noop, assert_ok,
-	codec::Decode,
-	traits::{
-		schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable,
-	},
+	traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable},
 };
-use frame_system::{Pallet as System, RawOrigin};
-use sp_runtime::traits::{BadOrigin, Bounded, One};
+use frame_system::RawOrigin;
+use sp_core::H256;
+use sp_runtime::{traits::Bounded, BoundedVec};
 
 use crate::Pallet as Democracy;
 
+const REFERENDUM_COUNT_HINT: u32 = 10;
 const SEED: u32 = 0;
-const MAX_REFERENDUMS: u32 = 99;
-const MAX_SECONDERS: u32 = 100;
-const MAX_BYTES: u32 = 16_384;
-
-fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
-	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
-}
 
 fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
 	let caller: T::AccountId = account(name, index, SEED);
@@ -49,37 +41,32 @@ fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
 	caller
 }
 
-fn add_proposal<T: Config>(n: u32) -> Result<T::Hash, &'static str> {
+fn make_proposal<T: Config>(n: u32) -> BoundedCallOf<T> {
+	let call: CallOf<T> = frame_system::Call::remark { remark: n.encode() }.into();
+	<T as Config>::Preimages::bound(call).unwrap()
+}
+
+fn add_proposal<T: Config>(n: u32) -> Result<H256, &'static str> {
 	let other = funded_account::<T>("proposer", n);
 	let value = T::MinimumDeposit::get();
-	let proposal_hash: T::Hash = T::Hashing::hash_of(&n);
-
-	Democracy::<T>::propose(RawOrigin::Signed(other).into(), proposal_hash, value)?;
-
-	Ok(proposal_hash)
+	let proposal = make_proposal::<T>(n);
+	Democracy::<T>::propose(RawOrigin::Signed(other).into(), proposal.clone(), value)?;
+	Ok(proposal.hash())
 }
 
-fn add_referendum<T: Config>(n: u32) -> Result<ReferendumIndex, &'static str> {
-	let proposal_hash: T::Hash = T::Hashing::hash_of(&n);
+fn add_referendum<T: Config>(n: u32) -> (ReferendumIndex, H256) {
 	let vote_threshold = VoteThreshold::SimpleMajority;
-
-	Democracy::<T>::inject_referendum(
-		T::LaunchPeriod::get(),
-		proposal_hash,
-		vote_threshold,
-		0u32.into(),
-	);
-	let referendum_index: ReferendumIndex = ReferendumCount::<T>::get() - 1;
-	T::Scheduler::schedule_named(
-		(DEMOCRACY_ID, referendum_index).encode(),
-		DispatchTime::At(2u32.into()),
-		None,
-		63,
-		frame_system::RawOrigin::Root.into(),
-		Call::enact_proposal { proposal_hash, index: referendum_index }.into(),
+	let proposal = make_proposal::<T>(n);
+	let hash = proposal.hash();
+	(
+		Democracy::<T>::inject_referendum(
+			T::LaunchPeriod::get(),
+			proposal,
+			vote_threshold,
+			0u32.into(),
+		),
+		hash,
 	)
-	.map_err(|_| "failed to schedule named")?;
-	Ok(referendum_index)
 }
 
 fn account_vote<T: Config>(b: BalanceOf<T>) -> AccountVote<BalanceOf<T>> {
@@ -97,95 +84,90 @@ benchmarks! {
 		}
 
 		let caller = funded_account::<T>("caller", 0);
-		let proposal_hash: T::Hash = T::Hashing::hash_of(&0);
+		let proposal = make_proposal::<T>(0);
 		let value = T::MinimumDeposit::get();
 		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller), proposal_hash, value)
+	}: _(RawOrigin::Signed(caller), proposal, value)
 	verify {
 		assert_eq!(Democracy::<T>::public_props().len(), p as usize, "Proposals not created.");
 	}
 
 	second {
-		let s in 0 .. MAX_SECONDERS;
-
 		let caller = funded_account::<T>("caller", 0);
-		let proposal_hash = add_proposal::<T>(s)?;
+		add_proposal::<T>(0)?;
 
 		// Create s existing "seconds"
-		for i in 0 .. s {
+		// we must reserve one deposit for the `proposal` and one for our benchmarked `second` call.
+		for i in 0 .. T::MaxDeposits::get() - 2 {
 			let seconder = funded_account::<T>("seconder", i);
-			Democracy::<T>::second(RawOrigin::Signed(seconder).into(), 0, u32::MAX)?;
+			Democracy::<T>::second(RawOrigin::Signed(seconder).into(), 0)?;
 		}
 
 		let deposits = Democracy::<T>::deposit_of(0).ok_or("Proposal not created")?;
-		assert_eq!(deposits.0.len(), (s + 1) as usize, "Seconds not recorded");
+		assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded");
 		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller), 0, u32::MAX)
+	}: _(RawOrigin::Signed(caller), 0)
 	verify {
 		let deposits = Democracy::<T>::deposit_of(0).ok_or("Proposal not created")?;
-		assert_eq!(deposits.0.len(), (s + 2) as usize, "`second` benchmark did not work");
+		assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work");
 	}
 
 	vote_new {
-		let r in 1 .. MAX_REFERENDUMS;
-
 		let caller = funded_account::<T>("caller", 0);
 		let account_vote = account_vote::<T>(100u32.into());
 
 		// We need to create existing direct votes
-		for i in 0 .. r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
+		for i in 0 .. T::MaxVotes::get() - 1 {
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
 		}
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
 			_ => return Err("Votes are not direct".into()),
 		};
-		assert_eq!(votes.len(), r as usize, "Votes were not recorded.");
+		assert_eq!(votes.len(), (T::MaxVotes::get() - 1) as usize, "Votes were not recorded.");
 
-		let referendum_index = add_referendum::<T>(r)?;
+		let ref_index = add_referendum::<T>(T::MaxVotes::get() - 1).0;
 		whitelist_account!(caller);
-	}: vote(RawOrigin::Signed(caller.clone()), referendum_index, account_vote)
+	}: vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote)
 	verify {
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
 			_ => return Err("Votes are not direct".into()),
 		};
-		assert_eq!(votes.len(), (r + 1) as usize, "Vote was not recorded.");
+		assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded.");
 	}
 
 	vote_existing {
-		let r in 1 .. MAX_REFERENDUMS;
-
 		let caller = funded_account::<T>("caller", 0);
 		let account_vote = account_vote::<T>(100u32.into());
 
 		// We need to create existing direct votes
-		for i in 0 ..=r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
+		for i in 0..T::MaxVotes::get() {
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
 		}
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
 			_ => return Err("Votes are not direct".into()),
 		};
-		assert_eq!(votes.len(), (r + 1) as usize, "Votes were not recorded.");
+		assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Votes were not recorded.");
 
 		// Change vote from aye to nay
 		let nay = Vote { aye: false, conviction: Conviction::Locked1x };
 		let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() };
-		let referendum_index = Democracy::<T>::referendum_count() - 1;
+		let ref_index = Democracy::<T>::referendum_count() - 1;
 
 		// This tests when a user changes a vote
 		whitelist_account!(caller);
-	}: vote(RawOrigin::Signed(caller.clone()), referendum_index, new_vote)
+	}: vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote)
 	verify {
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
 			_ => return Err("Votes are not direct".into()),
 		};
-		assert_eq!(votes.len(), (r + 1) as usize, "Vote was incorrectly added");
-		let referendum_info = Democracy::<T>::referendum_info(referendum_index)
+		assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added");
+		let referendum_info = Democracy::<T>::referendum_info(ref_index)
 			.ok_or("referendum doesn't exist")?;
 		let tally =  match referendum_info {
 			ReferendumInfo::Ongoing(r) => r.tally,
@@ -196,61 +178,55 @@ benchmarks! {
 
 	emergency_cancel {
 		let origin = T::CancellationOrigin::successful_origin();
-		let referendum_index = add_referendum::<T>(0)?;
-		assert_ok!(Democracy::<T>::referendum_status(referendum_index));
-	}: _<T::RuntimeOrigin>(origin, referendum_index)
+		let ref_index = add_referendum::<T>(0).0;
+		assert_ok!(Democracy::<T>::referendum_status(ref_index));
+	}: _<T::RuntimeOrigin>(origin, ref_index)
 	verify {
 		// Referendum has been canceled
 		assert_noop!(
-			Democracy::<T>::referendum_status(referendum_index),
+			Democracy::<T>::referendum_status(ref_index),
 			Error::<T>::ReferendumInvalid,
 		);
 	}
 
 	blacklist {
-		let p in 1 .. T::MaxProposals::get();
-
 		// Place our proposal at the end to make sure it's worst case.
-		for i in 0 .. p - 1 {
+		for i in 0 .. T::MaxProposals::get() - 1 {
 			add_proposal::<T>(i)?;
 		}
 		// We should really add a lot of seconds here, but we're not doing it elsewhere.
 
+		// Add a referendum of our proposal.
+		let (ref_index, hash) = add_referendum::<T>(0);
+		assert_ok!(Democracy::<T>::referendum_status(ref_index));
 		// Place our proposal in the external queue, too.
-		let hash = T::Hashing::hash_of(&0);
 		assert_ok!(
-			Democracy::<T>::external_propose(T::ExternalOrigin::successful_origin(), hash)
+			Democracy::<T>::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::<T>(0))
 		);
 		let origin = T::BlacklistOrigin::successful_origin();
-		// Add a referendum of our proposal.
-		let referendum_index = add_referendum::<T>(0)?;
-		assert_ok!(Democracy::<T>::referendum_status(referendum_index));
-	}: _<T::RuntimeOrigin>(origin, hash, Some(referendum_index))
+	}: _<T::RuntimeOrigin>(origin, hash, Some(ref_index))
 	verify {
 		// Referendum has been canceled
 		assert_noop!(
-			Democracy::<T>::referendum_status(referendum_index),
+			Democracy::<T>::referendum_status(ref_index),
 			Error::<T>::ReferendumInvalid
 		);
 	}
 
 	// Worst case scenario, we external propose a previously blacklisted proposal
 	external_propose {
-		let v in 1 .. MAX_VETOERS as u32;
-
 		let origin = T::ExternalOrigin::successful_origin();
-		let proposal_hash = T::Hashing::hash_of(&0);
+		let proposal = make_proposal::<T>(0);
 		// Add proposal to blacklist with block number 0
 
-		let addresses = (0..v)
+		let addresses: BoundedVec<_, _> = (0..(T::MaxBlacklisted::get() - 1))
 			.into_iter()
 			.map(|i| account::<T::AccountId>("blacklist", i, SEED))
-			.collect::<Vec<_>>();
-		Blacklist::<T>::insert(
-			proposal_hash,
-			(T::BlockNumber::zero(), addresses),
-		);
-	}: _<T::RuntimeOrigin>(origin, proposal_hash)
+			.collect::<Vec<_>>()
+			.try_into()
+			.unwrap();
+		Blacklist::<T>::insert(proposal.hash(), (T::BlockNumber::zero(), addresses));
+	}: _<T::RuntimeOrigin>(origin, proposal)
 	verify {
 		// External proposal created
 		ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -258,8 +234,8 @@ benchmarks! {
 
 	external_propose_majority {
 		let origin = T::ExternalMajorityOrigin::successful_origin();
-		let proposal_hash = T::Hashing::hash_of(&0);
-	}: _<T::RuntimeOrigin>(origin, proposal_hash)
+		let proposal = make_proposal::<T>(0);
+	}: _<T::RuntimeOrigin>(origin, proposal)
 	verify {
 		// External proposal created
 		ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -267,8 +243,8 @@ benchmarks! {
 
 	external_propose_default {
 		let origin = T::ExternalDefaultOrigin::successful_origin();
-		let proposal_hash = T::Hashing::hash_of(&0);
-	}: _<T::RuntimeOrigin>(origin, proposal_hash)
+		let proposal = make_proposal::<T>(0);
+	}: _<T::RuntimeOrigin>(origin, proposal)
 	verify {
 		// External proposal created
 		ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -276,8 +252,9 @@ benchmarks! {
 
 	fast_track {
 		let origin_propose = T::ExternalDefaultOrigin::successful_origin();
-		let proposal_hash: T::Hash = T::Hashing::hash_of(&0);
-		Democracy::<T>::external_propose_default(origin_propose, proposal_hash)?;
+		let proposal = make_proposal::<T>(0);
+		let proposal_hash = proposal.hash();
+		Democracy::<T>::external_propose_default(origin_propose, proposal)?;
 
 		// NOTE: Instant origin may invoke a little bit more logic, but may not always succeed.
 		let origin_fast_track = T::FastTrackOrigin::successful_origin();
@@ -289,17 +266,15 @@ benchmarks! {
 	}
 
 	veto_external {
-		// Existing veto-ers
-		let v in 0 .. MAX_VETOERS as u32;
-
-		let proposal_hash: T::Hash = T::Hashing::hash_of(&v);
+		let proposal = make_proposal::<T>(0);
+		let proposal_hash = proposal.hash();
 
 		let origin_propose = T::ExternalDefaultOrigin::successful_origin();
-		Democracy::<T>::external_propose_default(origin_propose, proposal_hash)?;
+		Democracy::<T>::external_propose_default(origin_propose, proposal)?;
 
-		let mut vetoers: Vec<T::AccountId> = Vec::new();
-		for i in 0 .. v {
-			vetoers.push(account::<T::AccountId>("vetoer", i, SEED));
+		let mut vetoers: BoundedVec<T::AccountId, _> = Default::default();
+		for i in 0 .. (T::MaxBlacklisted::get() - 1) {
+			vetoers.try_push(account::<T::AccountId>("vetoer", i, SEED)).unwrap();
 		}
 		vetoers.sort();
 		Blacklist::<T>::insert(proposal_hash, (T::BlockNumber::zero(), vetoers));
@@ -310,42 +285,27 @@ benchmarks! {
 	verify {
 		assert!(NextExternal::<T>::get().is_none());
 		let (_, new_vetoers) = <Blacklist<T>>::get(&proposal_hash).ok_or("no blacklist")?;
-		assert_eq!(new_vetoers.len(), (v + 1) as usize, "vetoers not added");
+		assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added");
 	}
 
 	cancel_proposal {
-		let p in 1 .. T::MaxProposals::get();
-
 		// Place our proposal at the end to make sure it's worst case.
-		for i in 0 .. p {
+		for i in 0 .. T::MaxProposals::get() {
 			add_proposal::<T>(i)?;
 		}
-
 		let cancel_origin = T::CancelProposalOrigin::successful_origin();
 	}: _<T::RuntimeOrigin>(cancel_origin, 0)
 
 	cancel_referendum {
-		let referendum_index = add_referendum::<T>(0)?;
-	}: _(RawOrigin::Root, referendum_index)
-
-	cancel_queued {
-		let r in 1 .. MAX_REFERENDUMS;
-
-		for i in 0..r {
-			add_referendum::<T>(i)?; // This add one element in the scheduler
-		}
-
-		let referendum_index = add_referendum::<T>(r)?;
-	}: _(RawOrigin::Root, referendum_index)
+		let ref_index = add_referendum::<T>(0).0;
+	}: _(RawOrigin::Root, ref_index)
 
-	// This measures the path of `launch_next` external. Not currently used as we simply
-	// assume the weight is `MaxBlockWeight` when executing.
 	#[extra]
 	on_initialize_external {
-		let r in 0 .. MAX_REFERENDUMS;
+		let r in 0 .. REFERENDUM_COUNT_HINT;
 
 		for i in 0..r {
-			add_referendum::<T>(i)?;
+			add_referendum::<T>(i);
 		}
 
 		assert_eq!(Democracy::<T>::referendum_count(), r, "referenda not created");
@@ -354,8 +314,8 @@ benchmarks! {
 		LastTabledWasExternal::<T>::put(false);
 
 		let origin = T::ExternalMajorityOrigin::successful_origin();
-		let proposal_hash = T::Hashing::hash_of(&r);
-		let call = Call::<T>::external_propose_majority { proposal_hash };
+		let proposal = make_proposal::<T>(r);
+		let call = Call::<T>::external_propose_majority { proposal };
 		call.dispatch_bypass_filter(origin)?;
 		// External proposal created
 		ensure!(<NextExternal<T>>::exists(), "External proposal didn't work");
@@ -379,14 +339,12 @@ benchmarks! {
 		}
 	}
 
-	// This measures the path of `launch_next` public. Not currently used as we simply
-	// assume the weight is `MaxBlockWeight` when executing.
 	#[extra]
 	on_initialize_public {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		for i in 0..r {
-			add_referendum::<T>(i)?;
+			add_referendum::<T>(i);
 		}
 
 		assert_eq!(Democracy::<T>::referendum_count(), r, "referenda not created");
@@ -415,10 +373,10 @@ benchmarks! {
 
 	// No launch no maturing referenda.
 	on_initialize_base {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		for i in 0..r {
-			add_referendum::<T>(i)?;
+			add_referendum::<T>(i);
 		}
 
 		for (key, mut info) in ReferendumInfoOf::<T>::iter() {
@@ -445,10 +403,10 @@ benchmarks! {
 	}
 
 	on_initialize_base_with_launch_period {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		for i in 0..r {
-			add_referendum::<T>(i)?;
+			add_referendum::<T>(i);
 		}
 
 		for (key, mut info) in ReferendumInfoOf::<T>::iter() {
@@ -477,7 +435,7 @@ benchmarks! {
 	}
 
 	delegate {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		let initial_balance: BalanceOf<T> = 100u32.into();
 		let delegated_balance: BalanceOf<T> = 1000u32.into();
@@ -504,8 +462,8 @@ benchmarks! {
 		let account_vote = account_vote::<T>(initial_balance);
 		// We need to create existing direct votes for the `new_delegate`
 		for i in 0..r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote)?;
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_index, account_vote)?;
 		}
 		let votes = match VotingOf::<T>::get(&new_delegate) {
 			Voting::Direct { votes, .. } => votes,
@@ -529,7 +487,7 @@ benchmarks! {
 	}
 
 	undelegate {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		let initial_balance: BalanceOf<T> = 100u32.into();
 		let delegated_balance: BalanceOf<T> = 1000u32.into();
@@ -553,10 +511,10 @@ benchmarks! {
 		// We need to create votes direct votes for the `delegate`
 		let account_vote = account_vote::<T>(initial_balance);
 		for i in 0..r {
-			let ref_idx = add_referendum::<T>(i)?;
+			let ref_index = add_referendum::<T>(i).0;
 			Democracy::<T>::vote(
 				RawOrigin::Signed(the_delegate.clone()).into(),
-				ref_idx,
+				ref_index,
 				account_vote
 			)?;
 		}
@@ -580,71 +538,9 @@ benchmarks! {
 
 	}: _(RawOrigin::Root)
 
-	note_preimage {
-		// Num of bytes in encoded proposal
-		let b in 0 .. MAX_BYTES;
-
-		let caller = funded_account::<T>("caller", 0);
-		let encoded_proposal = vec![1; b as usize];
-		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller), encoded_proposal.clone())
-	verify {
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		match Preimages::<T>::get(proposal_hash) {
-			Some(PreimageStatus::Available { .. }) => (),
-			_ => return Err("preimage not available".into())
-		}
-	}
-
-	note_imminent_preimage {
-		// Num of bytes in encoded proposal
-		let b in 0 .. MAX_BYTES;
-
-		// d + 1 to include the one we are testing
-		let encoded_proposal = vec![1; b as usize];
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		let block_number = T::BlockNumber::one();
-		Preimages::<T>::insert(&proposal_hash, PreimageStatus::Missing(block_number));
-
-		let caller = funded_account::<T>("caller", 0);
-		let encoded_proposal = vec![1; b as usize];
-		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller), encoded_proposal.clone())
-	verify {
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		match Preimages::<T>::get(proposal_hash) {
-			Some(PreimageStatus::Available { .. }) => (),
-			_ => return Err("preimage not available".into())
-		}
-	}
-
-	reap_preimage {
-		// Num of bytes in encoded proposal
-		let b in 0 .. MAX_BYTES;
-
-		let encoded_proposal = vec![1; b as usize];
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-
-		let submitter = funded_account::<T>("submitter", b);
-		Democracy::<T>::note_preimage(RawOrigin::Signed(submitter).into(), encoded_proposal.clone())?;
-
-		// We need to set this otherwise we get `Early` error.
-		let block_number = T::VotingPeriod::get() + T::EnactmentPeriod::get() + T::BlockNumber::one();
-		System::<T>::set_block_number(block_number);
-
-		assert!(Preimages::<T>::contains_key(proposal_hash));
-
-		let caller = funded_account::<T>("caller", 0);
-		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller), proposal_hash, u32::MAX)
-	verify {
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		assert!(!Preimages::<T>::contains_key(proposal_hash));
-	}
-
 	// Test when unlock will remove locks
 	unlock_remove {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		let locker = funded_account::<T>("locker", 0);
 		let locker_lookup = T::Lookup::unlookup(locker.clone());
@@ -653,9 +549,9 @@ benchmarks! {
 		let small_vote = account_vote::<T>(base_balance);
 		// Vote and immediately unvote
 		for i in 0 .. r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?;
-			Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_idx)?;
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
+			Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
 		}
 
 		let caller = funded_account::<T>("caller", 0);
@@ -669,7 +565,7 @@ benchmarks! {
 
 	// Test when unlock will set a new value
 	unlock_set {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 0 .. (T::MaxVotes::get() - 1);
 
 		let locker = funded_account::<T>("locker", 0);
 		let locker_lookup = T::Lookup::unlookup(locker.clone());
@@ -677,14 +573,14 @@ benchmarks! {
 		let base_balance: BalanceOf<T> = 100u32.into();
 		let small_vote = account_vote::<T>(base_balance);
 		for i in 0 .. r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?;
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
 		}
 
 		// Create a big vote so lock increases
 		let big_vote = account_vote::<T>(base_balance * 10u32.into());
-		let referendum_index = add_referendum::<T>(r)?;
-		Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), referendum_index, big_vote)?;
+		let ref_index = add_referendum::<T>(r).0;
+		Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, big_vote)?;
 
 		let votes = match VotingOf::<T>::get(&locker) {
 			Voting::Direct { votes, .. } => votes,
@@ -695,7 +591,7 @@ benchmarks! {
 		let voting = VotingOf::<T>::get(&locker);
 		assert_eq!(voting.locked_balance(), base_balance * 10u32.into());
 
-		Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), referendum_index)?;
+		Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
 
 		let caller = funded_account::<T>("caller", 0);
 		whitelist_account!(caller);
@@ -709,18 +605,18 @@ benchmarks! {
 
 		let voting = VotingOf::<T>::get(&locker);
 		// Note that we may want to add a `get_lock` api to actually verify
-		assert_eq!(voting.locked_balance(), base_balance);
+		assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() });
 	}
 
 	remove_vote {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 1 .. T::MaxVotes::get();
 
 		let caller = funded_account::<T>("caller", 0);
 		let account_vote = account_vote::<T>(100u32.into());
 
 		for i in 0 .. r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
 		}
 
 		let votes = match VotingOf::<T>::get(&caller) {
@@ -729,9 +625,9 @@ benchmarks! {
 		};
 		assert_eq!(votes.len(), r as usize, "Votes not created");
 
-		let referendum_index = r - 1;
+		let ref_index = r - 1;
 		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller.clone()), referendum_index)
+	}: _(RawOrigin::Signed(caller.clone()), ref_index)
 	verify {
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
@@ -742,15 +638,15 @@ benchmarks! {
 
 	// Worst case is when target == caller and referendum is ongoing
 	remove_other_vote {
-		let r in 1 .. MAX_REFERENDUMS;
+		let r in 1 .. T::MaxVotes::get();
 
 		let caller = funded_account::<T>("caller", r);
 		let caller_lookup = T::Lookup::unlookup(caller.clone());
 		let account_vote = account_vote::<T>(100u32.into());
 
 		for i in 0 .. r {
-			let ref_idx = add_referendum::<T>(i)?;
-			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?;
+			let ref_index = add_referendum::<T>(i).0;
+			Democracy::<T>::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?;
 		}
 
 		let votes = match VotingOf::<T>::get(&caller) {
@@ -759,9 +655,9 @@ benchmarks! {
 		};
 		assert_eq!(votes.len(), r as usize, "Votes not created");
 
-		let referendum_index = r - 1;
+		let ref_index = r - 1;
 		whitelist_account!(caller);
-	}: _(RawOrigin::Signed(caller.clone()), caller_lookup, referendum_index)
+	}: _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index)
 	verify {
 		let votes = match VotingOf::<T>::get(&caller) {
 			Voting::Direct { votes, .. } => votes,
@@ -770,54 +666,6 @@ benchmarks! {
 		assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed");
 	}
 
-	#[extra]
-	enact_proposal_execute {
-		// Num of bytes in encoded proposal
-		let b in 0 .. MAX_BYTES;
-
-		let proposer = funded_account::<T>("proposer", 0);
-		let raw_call = Call::note_preimage { encoded_proposal: vec![1; b as usize] };
-		let generic_call: T::Proposal = raw_call.into();
-		let encoded_proposal = generic_call.encode();
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		Democracy::<T>::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?;
-
-		match Preimages::<T>::get(proposal_hash) {
-			Some(PreimageStatus::Available { .. }) => (),
-			_ => return Err("preimage not available".into())
-		}
-	}: enact_proposal(RawOrigin::Root, proposal_hash, 0)
-	verify {
-		// Fails due to mismatched origin
-		assert_last_event::<T>(Event::<T>::Executed { ref_index: 0, result: Err(BadOrigin.into()) }.into());
-	}
-
-	#[extra]
-	enact_proposal_slash {
-		// Num of bytes in encoded proposal
-		let b in 0 .. MAX_BYTES;
-
-		let proposer = funded_account::<T>("proposer", 0);
-		// Random invalid bytes
-		let encoded_proposal = vec![200; b as usize];
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		Democracy::<T>::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?;
-
-		match Preimages::<T>::get(proposal_hash) {
-			Some(PreimageStatus::Available { .. }) => (),
-			_ => return Err("preimage not available".into())
-		}
-		let origin = RawOrigin::Root.into();
-		let call = Call::<T>::enact_proposal { proposal_hash, index: 0 }.encode();
-	}: {
-		assert_eq!(
-			<Call<T> as Decode>::decode(&mut &*call)
-				.expect("call is encoded above, encoding must be correct")
-				.dispatch_bypass_filter(origin),
-			Err(Error::<T>::PreimageInvalid.into())
-		);
-	}
-
 	impl_benchmark_test_suite!(
 		Democracy,
 		crate::tests::new_test_ext(),
diff --git a/substrate/frame/democracy/src/conviction.rs b/substrate/frame/democracy/src/conviction.rs
index 57d631e8c1f4cfb13b4e22c6085756940ac008c1..a938d8a4e6852afe0551cb8c78abf584f692d085 100644
--- a/substrate/frame/democracy/src/conviction.rs
+++ b/substrate/frame/democracy/src/conviction.rs
@@ -18,7 +18,7 @@
 //! The conviction datatype.
 
 use crate::types::Delegations;
-use codec::{Decode, Encode};
+use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
 use sp_runtime::{
 	traits::{Bounded, CheckedDiv, CheckedMul, Zero},
@@ -27,7 +27,19 @@ use sp_runtime::{
 use sp_std::{prelude::*, result::Result};
 
 /// A value denoting the strength of conviction of a vote.
-#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)]
+#[derive(
+	Encode,
+	MaxEncodedLen,
+	Decode,
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	RuntimeDebug,
+	TypeInfo,
+)]
 pub enum Conviction {
 	/// 0.1x votes, unlocked.
 	None,
diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs
index 3c1be1910399839776734602fb6dc04fb9ef3d4a..cf954d4800eee6c8e24eb6df5f8e92b1022e7620 100644
--- a/substrate/frame/democracy/src/lib.rs
+++ b/substrate/frame/democracy/src/lib.rs
@@ -152,21 +152,20 @@
 #![recursion_limit = "256"]
 #![cfg_attr(not(feature = "std"), no_std)]
 
-use codec::{Decode, Encode, Input};
+use codec::{Decode, Encode};
 use frame_support::{
 	ensure,
 	traits::{
 		defensive_prelude::*,
-		schedule::{DispatchTime, Named as ScheduleNamed},
-		BalanceStatus, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced,
-		ReservableCurrency, WithdrawReasons,
+		schedule::{v3::Named as ScheduleNamed, DispatchTime},
+		Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage,
+		ReservableCurrency, StorePreimage, WithdrawReasons,
 	},
 	weights::Weight,
 };
-use scale_info::TypeInfo;
 use sp_runtime::{
-	traits::{Bounded, Dispatchable, Hash, Saturating, StaticLookup, Zero},
-	ArithmeticError, DispatchError, DispatchResult, RuntimeDebug,
+	traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero},
+	ArithmeticError, DispatchError, DispatchResult,
 };
 use sp_std::prelude::*;
 
@@ -188,12 +187,9 @@ mod tests;
 #[cfg(feature = "runtime-benchmarks")]
 pub mod benchmarking;
 
-const DEMOCRACY_ID: LockIdentifier = *b"democrac";
+pub mod migrations;
 
-/// The maximum number of vetoers on a single proposal used to compute Weight.
-///
-/// NOTE: This is not enforced by any logic.
-pub const MAX_VETOERS: u32 = 100;
+const DEMOCRACY_ID: LockIdentifier = *b"democrac";
 
 /// A proposal index.
 pub type PropIndex = u32;
@@ -206,58 +202,36 @@ type BalanceOf<T> =
 type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
 	<T as frame_system::Config>::AccountId,
 >>::NegativeImbalance;
+pub type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
+pub type BoundedCallOf<T> = Bounded<CallOf<T>>;
 type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
 
-#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
-pub enum PreimageStatus<AccountId, Balance, BlockNumber> {
-	/// The preimage is imminently needed at the argument.
-	Missing(BlockNumber),
-	/// The preimage is available.
-	Available {
-		data: Vec<u8>,
-		provider: AccountId,
-		deposit: Balance,
-		since: BlockNumber,
-		/// None if it's not imminent.
-		expiry: Option<BlockNumber>,
-	},
-}
-
-impl<AccountId, Balance, BlockNumber> PreimageStatus<AccountId, Balance, BlockNumber> {
-	fn to_missing_expiry(self) -> Option<BlockNumber> {
-		match self {
-			PreimageStatus::Missing(expiry) => Some(expiry),
-			_ => None,
-		}
-	}
-}
-
-// A value placed in storage that represents the current version of the Democracy storage.
-// This value is used by the `on_runtime_upgrade` logic to determine whether we run
-// storage migration logic.
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-enum Releases {
-	V1,
-}
-
 #[frame_support::pallet]
 pub mod pallet {
 	use super::{DispatchResult, *};
 	use frame_support::pallet_prelude::*;
 	use frame_system::pallet_prelude::*;
+	use sp_core::H256;
+
+	/// The current storage version.
+	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
 
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
-	#[pallet::without_storage_info]
+	#[pallet::storage_version(STORAGE_VERSION)]
 	pub struct Pallet<T>(_);
 
 	#[pallet::config]
 	pub trait Config: frame_system::Config + Sized {
-		type Proposal: Parameter
-			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
-			+ From<Call<Self>>;
+		type WeightInfo: WeightInfo;
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
+		/// The Scheduler.
+		type Scheduler: ScheduleNamed<Self::BlockNumber, CallOf<Self>, Self::PalletsOrigin>;
+
+		/// The Preimage provider.
+		type Preimages: QueryPreimage + StorePreimage;
+
 		/// Currency type for this pallet.
 		type Currency: ReservableCurrency<Self::AccountId>
 			+ LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>;
@@ -289,6 +263,39 @@ pub mod pallet {
 		#[pallet::constant]
 		type MinimumDeposit: Get<BalanceOf<Self>>;
 
+		/// Indicator for whether an emergency origin is even allowed to happen. Some chains may
+		/// want to set this permanently to `false`, others may want to condition it on things such
+		/// as an upgrade having happened recently.
+		#[pallet::constant]
+		type InstantAllowed: Get<bool>;
+
+		/// Minimum voting period allowed for a fast-track referendum.
+		#[pallet::constant]
+		type FastTrackVotingPeriod: Get<Self::BlockNumber>;
+
+		/// Period in blocks where an external proposal may not be re-submitted after being vetoed.
+		#[pallet::constant]
+		type CooloffPeriod: Get<Self::BlockNumber>;
+
+		/// The maximum number of votes for an account.
+		///
+		/// Also used to compute weight, an overly big value can
+		/// lead to extrinsic with very big weight: see `delegate` for instance.
+		#[pallet::constant]
+		type MaxVotes: Get<u32>;
+
+		/// The maximum number of public proposals that can exist at any time.
+		#[pallet::constant]
+		type MaxProposals: Get<u32>;
+
+		/// The maximum number of deposits a public proposal may have at any time.
+		#[pallet::constant]
+		type MaxDeposits: Get<u32>;
+
+		/// The maximum number of items which can be blacklisted.
+		#[pallet::constant]
+		type MaxBlacklisted: Get<u32>;
+
 		/// Origin from which the next tabled referendum may be forced. This is a normal
 		/// "super-majority-required" referendum.
 		type ExternalOrigin: EnsureOrigin<Self::RuntimeOrigin>;
@@ -311,16 +318,6 @@ pub mod pallet {
 		/// origin. It retains its threshold method.
 		type InstantOrigin: EnsureOrigin<Self::RuntimeOrigin>;
 
-		/// Indicator for whether an emergency origin is even allowed to happen. Some chains may
-		/// want to set this permanently to `false`, others may want to condition it on things such
-		/// as an upgrade having happened recently.
-		#[pallet::constant]
-		type InstantAllowed: Get<bool>;
-
-		/// Minimum voting period allowed for a fast-track referendum.
-		#[pallet::constant]
-		type FastTrackVotingPeriod: Get<Self::BlockNumber>;
-
 		/// Origin from which any referendum may be cancelled in an emergency.
 		type CancellationOrigin: EnsureOrigin<Self::RuntimeOrigin>;
 
@@ -331,79 +328,39 @@ pub mod pallet {
 		type CancelProposalOrigin: EnsureOrigin<Self::RuntimeOrigin>;
 
 		/// Origin for anyone able to veto proposals.
-		///
-		/// # Warning
-		///
-		/// The number of Vetoers for a proposal must be small, extrinsics are weighted according to
-		/// [MAX_VETOERS](./const.MAX_VETOERS.html)
 		type VetoOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
 
-		/// Period in blocks where an external proposal may not be re-submitted after being vetoed.
-		#[pallet::constant]
-		type CooloffPeriod: Get<Self::BlockNumber>;
-
-		/// The amount of balance that must be deposited per byte of preimage stored.
-		#[pallet::constant]
-		type PreimageByteDeposit: Get<BalanceOf<Self>>;
-
-		/// An origin that can provide a preimage using operational extrinsics.
-		type OperationalPreimageOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
-
-		/// Handler for the unbalanced reduction when slashing a preimage deposit.
-		type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;
-
-		/// The Scheduler.
-		type Scheduler: ScheduleNamed<Self::BlockNumber, Self::Proposal, Self::PalletsOrigin>;
-
 		/// Overarching type of all pallets origins.
 		type PalletsOrigin: From<frame_system::RawOrigin<Self::AccountId>>;
 
-		/// The maximum number of votes for an account.
-		///
-		/// Also used to compute weight, an overly big value can
-		/// lead to extrinsic with very big weight: see `delegate` for instance.
-		#[pallet::constant]
-		type MaxVotes: Get<u32>;
-
-		/// Weight information for extrinsics in this pallet.
-		type WeightInfo: WeightInfo;
-
-		/// The maximum number of public proposals that can exist at any time.
-		#[pallet::constant]
-		type MaxProposals: Get<u32>;
+		/// Handler for the unbalanced reduction when slashing a preimage deposit.
+		type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;
 	}
 
-	// TODO: Refactor public proposal queue into its own pallet.
-	// https://github.com/paritytech/substrate/issues/5322
 	/// The number of (public) proposals that have been made so far.
 	#[pallet::storage]
 	#[pallet::getter(fn public_prop_count)]
 	pub type PublicPropCount<T> = StorageValue<_, PropIndex, ValueQuery>;
 
-	/// The public proposals. Unsorted. The second item is the proposal's hash.
+	/// The public proposals. Unsorted. The second item is the proposal.
 	#[pallet::storage]
 	#[pallet::getter(fn public_props)]
-	pub type PublicProps<T: Config> =
-		StorageValue<_, Vec<(PropIndex, T::Hash, T::AccountId)>, ValueQuery>;
+	pub type PublicProps<T: Config> = StorageValue<
+		_,
+		BoundedVec<(PropIndex, BoundedCallOf<T>, T::AccountId), T::MaxProposals>,
+		ValueQuery,
+	>;
 
 	/// Those who have locked a deposit.
 	///
 	/// TWOX-NOTE: Safe, as increasing integer keys are safe.
 	#[pallet::storage]
 	#[pallet::getter(fn deposit_of)]
-	pub type DepositOf<T: Config> =
-		StorageMap<_, Twox64Concat, PropIndex, (Vec<T::AccountId>, BalanceOf<T>)>;
-
-	/// Map of hashes to the proposal preimage, along with who registered it and their deposit.
-	/// The block number is the block at which it was deposited.
-	// TODO: Refactor Preimages into its own pallet.
-	// https://github.com/paritytech/substrate/issues/5322
-	#[pallet::storage]
-	pub type Preimages<T: Config> = StorageMap<
+	pub type DepositOf<T: Config> = StorageMap<
 		_,
-		Identity,
-		T::Hash,
-		PreimageStatus<T::AccountId, BalanceOf<T>, T::BlockNumber>,
+		Twox64Concat,
+		PropIndex,
+		(BoundedVec<T::AccountId, T::MaxDeposits>, BalanceOf<T>),
 	>;
 
 	/// The next free referendum index, aka the number of referenda started so far.
@@ -426,7 +383,7 @@ pub mod pallet {
 		_,
 		Twox64Concat,
 		ReferendumIndex,
-		ReferendumInfo<T::BlockNumber, T::Hash, BalanceOf<T>>,
+		ReferendumInfo<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>,
 	>;
 
 	/// All votes for a particular voter. We store the balance for the number of votes that we
@@ -438,14 +395,12 @@ pub mod pallet {
 		_,
 		Twox64Concat,
 		T::AccountId,
-		Voting<BalanceOf<T>, T::AccountId, T::BlockNumber>,
+		Voting<BalanceOf<T>, T::AccountId, T::BlockNumber, T::MaxVotes>,
 		ValueQuery,
 	>;
 
 	/// True if the last referendum tabled was submitted externally. False if it was a public
 	/// proposal.
-	// TODO: There should be any number of tabling origins, not just public and "external"
-	// (council). https://github.com/paritytech/substrate/issues/5322
 	#[pallet::storage]
 	pub type LastTabledWasExternal<T> = StorageValue<_, bool, ValueQuery>;
 
@@ -454,23 +409,21 @@ pub mod pallet {
 	/// - `LastTabledWasExternal` is `false`; or
 	/// - `PublicProps` is empty.
 	#[pallet::storage]
-	pub type NextExternal<T: Config> = StorageValue<_, (T::Hash, VoteThreshold)>;
+	pub type NextExternal<T: Config> = StorageValue<_, (BoundedCallOf<T>, VoteThreshold)>;
 
 	/// A record of who vetoed what. Maps proposal hash to a possible existent block number
 	/// (until when it may not be resubmitted) and who vetoed it.
 	#[pallet::storage]
-	pub type Blacklist<T: Config> =
-		StorageMap<_, Identity, T::Hash, (T::BlockNumber, Vec<T::AccountId>)>;
+	pub type Blacklist<T: Config> = StorageMap<
+		_,
+		Identity,
+		H256,
+		(T::BlockNumber, BoundedVec<T::AccountId, T::MaxBlacklisted>),
+	>;
 
 	/// Record of all proposals that have been subject to emergency cancellation.
 	#[pallet::storage]
-	pub type Cancellations<T: Config> = StorageMap<_, Identity, T::Hash, bool, ValueQuery>;
-
-	/// Storage version of the pallet.
-	///
-	/// New networks start with last version.
-	#[pallet::storage]
-	pub(crate) type StorageVersion<T> = StorageValue<_, Releases>;
+	pub type Cancellations<T: Config> = StorageMap<_, Identity, H256, bool, ValueQuery>;
 
 	#[pallet::genesis_config]
 	pub struct GenesisConfig<T: Config> {
@@ -490,7 +443,6 @@ pub mod pallet {
 			PublicPropCount::<T>::put(0 as PropIndex);
 			ReferendumCount::<T>::put(0 as ReferendumIndex);
 			LowestUnbaked::<T>::put(0 as ReferendumIndex);
-			StorageVersion::<T>::put(Releases::V1);
 		}
 	}
 
@@ -500,7 +452,7 @@ pub mod pallet {
 		/// A motion has been proposed by a public account.
 		Proposed { proposal_index: PropIndex, deposit: BalanceOf<T> },
 		/// A public proposal has been tabled for referendum vote.
-		Tabled { proposal_index: PropIndex, deposit: BalanceOf<T>, depositors: Vec<T::AccountId> },
+		Tabled { proposal_index: PropIndex, deposit: BalanceOf<T> },
 		/// An external proposal has been tabled.
 		ExternalTabled,
 		/// A referendum has begun.
@@ -511,31 +463,14 @@ pub mod pallet {
 		NotPassed { ref_index: ReferendumIndex },
 		/// A referendum has been cancelled.
 		Cancelled { ref_index: ReferendumIndex },
-		/// A proposal has been enacted.
-		Executed { ref_index: ReferendumIndex, result: DispatchResult },
 		/// An account has delegated their vote to another account.
 		Delegated { who: T::AccountId, target: T::AccountId },
 		/// An account has cancelled a previous delegation operation.
 		Undelegated { account: T::AccountId },
 		/// An external proposal has been vetoed.
-		Vetoed { who: T::AccountId, proposal_hash: T::Hash, until: T::BlockNumber },
-		/// A proposal's preimage was noted, and the deposit taken.
-		PreimageNoted { proposal_hash: T::Hash, who: T::AccountId, deposit: BalanceOf<T> },
-		/// A proposal preimage was removed and used (the deposit was returned).
-		PreimageUsed { proposal_hash: T::Hash, provider: T::AccountId, deposit: BalanceOf<T> },
-		/// A proposal could not be executed because its preimage was invalid.
-		PreimageInvalid { proposal_hash: T::Hash, ref_index: ReferendumIndex },
-		/// A proposal could not be executed because its preimage was missing.
-		PreimageMissing { proposal_hash: T::Hash, ref_index: ReferendumIndex },
-		/// A registered preimage was removed and the deposit collected by the reaper.
-		PreimageReaped {
-			proposal_hash: T::Hash,
-			provider: T::AccountId,
-			deposit: BalanceOf<T>,
-			reaper: T::AccountId,
-		},
+		Vetoed { who: T::AccountId, proposal_hash: H256, until: T::BlockNumber },
 		/// A proposal_hash has been blacklisted permanently.
-		Blacklisted { proposal_hash: T::Hash },
+		Blacklisted { proposal_hash: H256 },
 		/// An account has voted in a referendum
 		Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote<BalanceOf<T>> },
 		/// An account has secconded a proposal
@@ -564,20 +499,8 @@ pub mod pallet {
 		NoProposal,
 		/// Identity may not veto a proposal twice
 		AlreadyVetoed,
-		/// Preimage already noted
-		DuplicatePreimage,
-		/// Not imminent
-		NotImminent,
-		/// Too early
-		TooEarly,
-		/// Imminent
-		Imminent,
-		/// Preimage not found
-		PreimageMissing,
 		/// Vote given for invalid referendum
 		ReferendumInvalid,
-		/// Invalid preimage
-		PreimageInvalid,
 		/// No proposals waiting
 		NoneWaiting,
 		/// The given account did not vote on the referendum.
@@ -601,8 +524,8 @@ pub mod pallet {
 		WrongUpperBound,
 		/// Maximum number of votes reached.
 		MaxVotesReached,
-		/// Maximum number of proposals reached.
-		TooManyProposals,
+		/// Maximum number of items reached.
+		TooMany,
 		/// Voting period too low
 		VotingPeriodLow,
 	}
@@ -626,12 +549,10 @@ pub mod pallet {
 		/// - `value`: The amount of deposit (must be at least `MinimumDeposit`).
 		///
 		/// Emits `Proposed`.
-		///
-		/// Weight: `O(p)`
 		#[pallet::weight(T::WeightInfo::propose())]
 		pub fn propose(
 			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
+			proposal: BoundedCallOf<T>,
 			#[pallet::compact] value: BalanceOf<T>,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
@@ -640,7 +561,8 @@ pub mod pallet {
 			let index = Self::public_prop_count();
 			let real_prop_count = PublicProps::<T>::decode_len().unwrap_or(0) as u32;
 			let max_proposals = T::MaxProposals::get();
-			ensure!(real_prop_count < max_proposals, Error::<T>::TooManyProposals);
+			ensure!(real_prop_count < max_proposals, Error::<T>::TooMany);
+			let proposal_hash = proposal.hash();
 
 			if let Some((until, _)) = <Blacklist<T>>::get(proposal_hash) {
 				ensure!(
@@ -650,10 +572,14 @@ pub mod pallet {
 			}
 
 			T::Currency::reserve(&who, value)?;
+
+			let depositors = BoundedVec::<_, T::MaxDeposits>::truncate_from(vec![who.clone()]);
+			DepositOf::<T>::insert(index, (depositors, value));
+
 			PublicPropCount::<T>::put(index + 1);
-			<DepositOf<T>>::insert(index, (&[&who][..], value));
 
-			<PublicProps<T>>::append((index, proposal_hash, who));
+			PublicProps::<T>::try_append((index, proposal, who))
+				.map_err(|_| Error::<T>::TooMany)?;
 
 			Self::deposit_event(Event::<T>::Proposed { proposal_index: index, deposit: value });
 			Ok(())
@@ -665,23 +591,19 @@ pub mod pallet {
 		/// must have funds to cover the deposit, equal to the original deposit.
 		///
 		/// - `proposal`: The index of the proposal to second.
-		/// - `seconds_upper_bound`: an upper bound on the current number of seconds on this
-		///   proposal. Extrinsic is weighted according to this value with no refund.
-		///
-		/// Weight: `O(S)` where S is the number of seconds a proposal already has.
-		#[pallet::weight(T::WeightInfo::second(*seconds_upper_bound))]
+		#[pallet::weight(T::WeightInfo::second())]
 		pub fn second(
 			origin: OriginFor<T>,
 			#[pallet::compact] proposal: PropIndex,
-			#[pallet::compact] seconds_upper_bound: u32,
 		) -> DispatchResult {
 			let who = ensure_signed(origin)?;
 
 			let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::<T>::ProposalMissing)?;
-			ensure!(seconds <= seconds_upper_bound, Error::<T>::WrongUpperBound);
+			ensure!(seconds < T::MaxDeposits::get(), Error::<T>::TooMany);
 			let mut deposit = Self::deposit_of(proposal).ok_or(Error::<T>::ProposalMissing)?;
 			T::Currency::reserve(&who, deposit.1)?;
-			deposit.0.push(who.clone());
+			let ok = deposit.0.try_push(who.clone()).is_ok();
+			debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed");
 			<DepositOf<T>>::insert(proposal, deposit);
 			Self::deposit_event(Event::<T>::Seconded { seconder: who, prop_index: proposal });
 			Ok(())
@@ -694,12 +616,7 @@ pub mod pallet {
 		///
 		/// - `ref_index`: The index of the referendum to vote for.
 		/// - `vote`: The vote configuration.
-		///
-		/// Weight: `O(R)` where R is the number of referendums the voter has voted on.
-		#[pallet::weight(
-			T::WeightInfo::vote_new(T::MaxVotes::get())
-				.max(T::WeightInfo::vote_existing(T::MaxVotes::get()))
-		)]
+		#[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))]
 		pub fn vote(
 			origin: OriginFor<T>,
 			#[pallet::compact] ref_index: ReferendumIndex,
@@ -725,7 +642,7 @@ pub mod pallet {
 			T::CancellationOrigin::ensure_origin(origin)?;
 
 			let status = Self::referendum_status(ref_index)?;
-			let h = status.proposal_hash;
+			let h = status.proposal.hash();
 			ensure!(!<Cancellations<T>>::contains_key(h), Error::<T>::AlreadyCanceled);
 
 			<Cancellations<T>>::insert(h, true);
@@ -739,20 +656,20 @@ pub mod pallet {
 		/// The dispatch origin of this call must be `ExternalOrigin`.
 		///
 		/// - `proposal_hash`: The preimage hash of the proposal.
-		///
-		/// Weight: `O(V)` with V number of vetoers in the blacklist of proposal.
-		///   Decoding vec of length V. Charged as maximum
-		#[pallet::weight(T::WeightInfo::external_propose(MAX_VETOERS))]
-		pub fn external_propose(origin: OriginFor<T>, proposal_hash: T::Hash) -> DispatchResult {
+		#[pallet::weight(T::WeightInfo::external_propose())]
+		pub fn external_propose(
+			origin: OriginFor<T>,
+			proposal: BoundedCallOf<T>,
+		) -> DispatchResult {
 			T::ExternalOrigin::ensure_origin(origin)?;
 			ensure!(!<NextExternal<T>>::exists(), Error::<T>::DuplicateProposal);
-			if let Some((until, _)) = <Blacklist<T>>::get(proposal_hash) {
+			if let Some((until, _)) = <Blacklist<T>>::get(proposal.hash()) {
 				ensure!(
 					<frame_system::Pallet<T>>::block_number() >= until,
 					Error::<T>::ProposalBlacklisted,
 				);
 			}
-			<NextExternal<T>>::put((proposal_hash, VoteThreshold::SuperMajorityApprove));
+			<NextExternal<T>>::put((proposal, VoteThreshold::SuperMajorityApprove));
 			Ok(())
 		}
 
@@ -770,10 +687,10 @@ pub mod pallet {
 		#[pallet::weight(T::WeightInfo::external_propose_majority())]
 		pub fn external_propose_majority(
 			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
+			proposal: BoundedCallOf<T>,
 		) -> DispatchResult {
 			T::ExternalMajorityOrigin::ensure_origin(origin)?;
-			<NextExternal<T>>::put((proposal_hash, VoteThreshold::SimpleMajority));
+			<NextExternal<T>>::put((proposal, VoteThreshold::SimpleMajority));
 			Ok(())
 		}
 
@@ -791,10 +708,10 @@ pub mod pallet {
 		#[pallet::weight(T::WeightInfo::external_propose_default())]
 		pub fn external_propose_default(
 			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
+			proposal: BoundedCallOf<T>,
 		) -> DispatchResult {
 			T::ExternalDefaultOrigin::ensure_origin(origin)?;
-			<NextExternal<T>>::put((proposal_hash, VoteThreshold::SuperMajorityAgainst));
+			<NextExternal<T>>::put((proposal, VoteThreshold::SuperMajorityAgainst));
 			Ok(())
 		}
 
@@ -805,7 +722,7 @@ pub mod pallet {
 		/// The dispatch of this call must be `FastTrackOrigin`.
 		///
 		/// - `proposal_hash`: The hash of the current external proposal.
-		/// - `voting_period`: The period that is allowed for voting on this proposal.
+		/// - `voting_period`: The period that is allowed for voting on this proposal. Increased to
 		/// 	Must be always greater than zero.
 		/// 	For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`.
 		/// - `delay`: The number of block after voting has ended in approval and this should be
@@ -817,7 +734,7 @@ pub mod pallet {
 		#[pallet::weight(T::WeightInfo::fast_track())]
 		pub fn fast_track(
 			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
+			proposal_hash: H256,
 			voting_period: T::BlockNumber,
 			delay: T::BlockNumber,
 		) -> DispatchResult {
@@ -836,20 +753,21 @@ pub mod pallet {
 				T::InstantOrigin::ensure_origin(ensure_instant)?;
 				ensure!(T::InstantAllowed::get(), Error::<T>::InstantNotAllowed);
 			}
+
 			ensure!(voting_period > T::BlockNumber::zero(), Error::<T>::VotingPeriodLow);
-			let (e_proposal_hash, threshold) =
+			let (ext_proposal, threshold) =
 				<NextExternal<T>>::get().ok_or(Error::<T>::ProposalMissing)?;
 			ensure!(
 				threshold != VoteThreshold::SuperMajorityApprove,
 				Error::<T>::NotSimpleMajority,
 			);
-			ensure!(proposal_hash == e_proposal_hash, Error::<T>::InvalidHash);
+			ensure!(proposal_hash == ext_proposal.hash(), Error::<T>::InvalidHash);
 
 			<NextExternal<T>>::kill();
 			let now = <frame_system::Pallet<T>>::block_number();
 			Self::inject_referendum(
 				now.saturating_add(voting_period),
-				proposal_hash,
+				ext_proposal,
 				threshold,
 				delay,
 			);
@@ -865,22 +783,24 @@ pub mod pallet {
 		/// Emits `Vetoed`.
 		///
 		/// Weight: `O(V + log(V))` where V is number of `existing vetoers`
-		#[pallet::weight(T::WeightInfo::veto_external(MAX_VETOERS))]
-		pub fn veto_external(origin: OriginFor<T>, proposal_hash: T::Hash) -> DispatchResult {
+		#[pallet::weight(T::WeightInfo::veto_external())]
+		pub fn veto_external(origin: OriginFor<T>, proposal_hash: H256) -> DispatchResult {
 			let who = T::VetoOrigin::ensure_origin(origin)?;
 
-			if let Some((e_proposal_hash, _)) = <NextExternal<T>>::get() {
-				ensure!(proposal_hash == e_proposal_hash, Error::<T>::ProposalMissing);
+			if let Some((ext_proposal, _)) = NextExternal::<T>::get() {
+				ensure!(proposal_hash == ext_proposal.hash(), Error::<T>::ProposalMissing);
 			} else {
 				return Err(Error::<T>::NoProposal.into())
 			}
 
 			let mut existing_vetoers =
-				<Blacklist<T>>::get(&proposal_hash).map(|pair| pair.1).unwrap_or_else(Vec::new);
+				<Blacklist<T>>::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default();
 			let insert_position =
 				existing_vetoers.binary_search(&who).err().ok_or(Error::<T>::AlreadyVetoed)?;
+			existing_vetoers
+				.try_insert(insert_position, who.clone())
+				.map_err(|_| Error::<T>::TooMany)?;
 
-			existing_vetoers.insert(insert_position, who.clone());
 			let until =
 				<frame_system::Pallet<T>>::block_number().saturating_add(T::CooloffPeriod::get());
 			<Blacklist<T>>::insert(&proposal_hash, (until, existing_vetoers));
@@ -907,21 +827,6 @@ pub mod pallet {
 			Ok(())
 		}
 
-		/// Cancel a proposal queued for enactment.
-		///
-		/// The dispatch origin of this call must be _Root_.
-		///
-		/// - `which`: The index of the referendum to cancel.
-		///
-		/// Weight: `O(D)` where `D` is the items in the dispatch queue. Weighted as `D = 10`.
-		#[pallet::weight((T::WeightInfo::cancel_queued(10), DispatchClass::Operational))]
-		pub fn cancel_queued(origin: OriginFor<T>, which: ReferendumIndex) -> DispatchResult {
-			ensure_root(origin)?;
-			T::Scheduler::cancel_named((DEMOCRACY_ID, which).encode())
-				.map_err(|_| Error::<T>::ProposalMissing)?;
-			Ok(())
-		}
-
 		/// Delegate the voting power (with some given conviction) of the sending account.
 		///
 		/// The balance delegated is locked for as long as it's delegated, and thereafter for the
@@ -991,135 +896,6 @@ pub mod pallet {
 			Ok(())
 		}
 
-		/// Register the preimage for an upcoming proposal. This doesn't require the proposal to be
-		/// in the dispatch queue but does require a deposit, returned once enacted.
-		///
-		/// The dispatch origin of this call must be _Signed_.
-		///
-		/// - `encoded_proposal`: The preimage of a proposal.
-		///
-		/// Emits `PreimageNoted`.
-		///
-		/// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit).
-		#[pallet::weight(T::WeightInfo::note_preimage(encoded_proposal.len() as u32))]
-		pub fn note_preimage(origin: OriginFor<T>, encoded_proposal: Vec<u8>) -> DispatchResult {
-			Self::note_preimage_inner(ensure_signed(origin)?, encoded_proposal)?;
-			Ok(())
-		}
-
-		/// Same as `note_preimage` but origin is `OperationalPreimageOrigin`.
-		#[pallet::weight((
-			T::WeightInfo::note_preimage(encoded_proposal.len() as u32),
-			DispatchClass::Operational,
-		))]
-		pub fn note_preimage_operational(
-			origin: OriginFor<T>,
-			encoded_proposal: Vec<u8>,
-		) -> DispatchResult {
-			let who = T::OperationalPreimageOrigin::ensure_origin(origin)?;
-			Self::note_preimage_inner(who, encoded_proposal)?;
-			Ok(())
-		}
-
-		/// Register the preimage for an upcoming proposal. This requires the proposal to be
-		/// in the dispatch queue. No deposit is needed. When this call is successful, i.e.
-		/// the preimage has not been uploaded before and matches some imminent proposal,
-		/// no fee is paid.
-		///
-		/// The dispatch origin of this call must be _Signed_.
-		///
-		/// - `encoded_proposal`: The preimage of a proposal.
-		///
-		/// Emits `PreimageNoted`.
-		///
-		/// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit).
-		#[pallet::weight(T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32))]
-		pub fn note_imminent_preimage(
-			origin: OriginFor<T>,
-			encoded_proposal: Vec<u8>,
-		) -> DispatchResultWithPostInfo {
-			Self::note_imminent_preimage_inner(ensure_signed(origin)?, encoded_proposal)?;
-			// We check that this preimage was not uploaded before in
-			// `note_imminent_preimage_inner`, thus this call can only be successful once. If
-			// successful, user does not pay a fee.
-			Ok(Pays::No.into())
-		}
-
-		/// Same as `note_imminent_preimage` but origin is `OperationalPreimageOrigin`.
-		#[pallet::weight((
-			T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32),
-			DispatchClass::Operational,
-		))]
-		pub fn note_imminent_preimage_operational(
-			origin: OriginFor<T>,
-			encoded_proposal: Vec<u8>,
-		) -> DispatchResultWithPostInfo {
-			let who = T::OperationalPreimageOrigin::ensure_origin(origin)?;
-			Self::note_imminent_preimage_inner(who, encoded_proposal)?;
-			// We check that this preimage was not uploaded before in
-			// `note_imminent_preimage_inner`, thus this call can only be successful once. If
-			// successful, user does not pay a fee.
-			Ok(Pays::No.into())
-		}
-
-		/// Remove an expired proposal preimage and collect the deposit.
-		///
-		/// The dispatch origin of this call must be _Signed_.
-		///
-		/// - `proposal_hash`: The preimage hash of a proposal.
-		/// - `proposal_length_upper_bound`: an upper bound on length of the proposal. Extrinsic is
-		///   weighted according to this value with no refund.
-		///
-		/// This will only work after `VotingPeriod` blocks from the time that the preimage was
-		/// noted, if it's the same account doing it. If it's a different account, then it'll only
-		/// work an additional `EnactmentPeriod` later.
-		///
-		/// Emits `PreimageReaped`.
-		///
-		/// Weight: `O(D)` where D is length of proposal.
-		#[pallet::weight(T::WeightInfo::reap_preimage(*proposal_len_upper_bound))]
-		pub fn reap_preimage(
-			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
-			#[pallet::compact] proposal_len_upper_bound: u32,
-		) -> DispatchResult {
-			let who = ensure_signed(origin)?;
-
-			ensure!(
-				Self::pre_image_data_len(proposal_hash)? <= proposal_len_upper_bound,
-				Error::<T>::WrongUpperBound,
-			);
-
-			let (provider, deposit, since, expiry) = <Preimages<T>>::get(&proposal_hash)
-				.and_then(|m| match m {
-					PreimageStatus::Available { provider, deposit, since, expiry, .. } =>
-						Some((provider, deposit, since, expiry)),
-					_ => None,
-				})
-				.ok_or(Error::<T>::PreimageMissing)?;
-
-			let now = <frame_system::Pallet<T>>::block_number();
-			let (voting, enactment) = (T::VotingPeriod::get(), T::EnactmentPeriod::get());
-			let additional = if who == provider { Zero::zero() } else { enactment };
-			ensure!(
-				now >= since.saturating_add(voting).saturating_add(additional),
-				Error::<T>::TooEarly
-			);
-			ensure!(expiry.map_or(true, |e| now > e), Error::<T>::Imminent);
-
-			let res =
-				T::Currency::repatriate_reserved(&provider, &who, deposit, BalanceStatus::Free);
-			debug_assert!(res.is_ok());
-			<Preimages<T>>::remove(&proposal_hash);
-			Self::deposit_event(Event::<T>::PreimageReaped {
-				proposal_hash,
-				provider,
-				deposit,
-				reaper: who,
-			});
-			Ok(())
-		}
-
 		/// Unlock tokens that have an expired lock.
 		///
 		/// The dispatch origin of this call must be _Signed_.
@@ -1127,10 +903,7 @@ pub mod pallet {
 		/// - `target`: The account to remove the lock on.
 		///
 		/// Weight: `O(R)` with R number of vote of target.
-		#[pallet::weight(
-			T::WeightInfo::unlock_set(T::MaxVotes::get())
-				.max(T::WeightInfo::unlock_remove(T::MaxVotes::get()))
-		)]
+		#[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))]
 		pub fn unlock(origin: OriginFor<T>, target: AccountIdLookupOf<T>) -> DispatchResult {
 			ensure_signed(origin)?;
 			let target = T::Lookup::lookup(target)?;
@@ -1199,17 +972,6 @@ pub mod pallet {
 			Ok(())
 		}
 
-		/// Enact a proposal from a referendum. For now we just make the weight be the maximum.
-		#[pallet::weight(T::BlockWeights::get().max_block)]
-		pub fn enact_proposal(
-			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
-			index: ReferendumIndex,
-		) -> DispatchResult {
-			ensure_root(origin)?;
-			Self::do_enact_proposal(proposal_hash, index)
-		}
-
 		/// Permanently place a proposal into the blacklist. This prevents it from ever being
 		/// proposed again.
 		///
@@ -1225,21 +987,21 @@ pub mod pallet {
 		///
 		/// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a
 		///   reasonable value).
-		#[pallet::weight((T::WeightInfo::blacklist(T::MaxProposals::get()), DispatchClass::Operational))]
+		#[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))]
 		pub fn blacklist(
 			origin: OriginFor<T>,
-			proposal_hash: T::Hash,
+			proposal_hash: H256,
 			maybe_ref_index: Option<ReferendumIndex>,
 		) -> DispatchResult {
 			T::BlacklistOrigin::ensure_origin(origin)?;
 
 			// Insert the proposal into the blacklist.
-			let permanent = (T::BlockNumber::max_value(), Vec::<T::AccountId>::new());
+			let permanent = (T::BlockNumber::max_value(), BoundedVec::<T::AccountId, _>::default());
 			Blacklist::<T>::insert(&proposal_hash, permanent);
 
 			// Remove the queued proposal, if it's there.
 			PublicProps::<T>::mutate(|props| {
-				if let Some(index) = props.iter().position(|p| p.1 == proposal_hash) {
+				if let Some(index) = props.iter().position(|p| p.1.hash() == proposal_hash) {
 					let (prop_index, ..) = props.remove(index);
 					if let Some((whos, amount)) = DepositOf::<T>::take(prop_index) {
 						for who in whos.into_iter() {
@@ -1250,14 +1012,14 @@ pub mod pallet {
 			});
 
 			// Remove the external queued referendum, if it's there.
-			if matches!(NextExternal::<T>::get(), Some((h, ..)) if h == proposal_hash) {
+			if matches!(NextExternal::<T>::get(), Some((p, ..)) if p.hash() == proposal_hash) {
 				NextExternal::<T>::kill();
 			}
 
 			// Remove the referendum, if it's there.
 			if let Some(ref_index) = maybe_ref_index {
 				if let Ok(status) = Self::referendum_status(ref_index) {
-					if status.proposal_hash == proposal_hash {
+					if status.proposal.hash() == proposal_hash {
 						Self::internal_cancel_referendum(ref_index);
 					}
 				}
@@ -1274,7 +1036,7 @@ pub mod pallet {
 		/// - `prop_index`: The index of the proposal to cancel.
 		///
 		/// Weight: `O(p)` where `p = PublicProps::<T>::decode_len()`
-		#[pallet::weight(T::WeightInfo::cancel_proposal(T::MaxProposals::get()))]
+		#[pallet::weight(T::WeightInfo::cancel_proposal())]
 		pub fn cancel_proposal(
 			origin: OriginFor<T>,
 			#[pallet::compact] prop_index: PropIndex,
@@ -1294,6 +1056,25 @@ pub mod pallet {
 	}
 }
 
+pub trait EncodeInto: Encode {
+	fn encode_into<T: AsMut<[u8]> + Default>(&self) -> T {
+		let mut t = T::default();
+		self.using_encoded(|data| {
+			if data.len() <= t.as_mut().len() {
+				t.as_mut()[0..data.len()].copy_from_slice(data);
+			} else {
+				// encoded self is too big to fit into a T. hash it and use the first bytes of that
+				// instead.
+				let hash = sp_io::hashing::blake2_256(data);
+				let l = t.as_mut().len().min(hash.len());
+				t.as_mut()[0..l].copy_from_slice(&hash[0..l]);
+			}
+		});
+		t
+	}
+}
+impl<T: Encode> EncodeInto for T {}
+
 impl<T: Config> Pallet<T> {
 	// exposed immutables.
 
@@ -1306,7 +1087,7 @@ impl<T: Config> Pallet<T> {
 	/// Get all referenda ready for tally at block `n`.
 	pub fn maturing_referenda_at(
 		n: T::BlockNumber,
-	) -> Vec<(ReferendumIndex, ReferendumStatus<T::BlockNumber, T::Hash, BalanceOf<T>>)> {
+	) -> Vec<(ReferendumIndex, ReferendumStatus<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>)> {
 		let next = Self::lowest_unbaked();
 		let last = Self::referendum_count();
 		Self::maturing_referenda_at_inner(n, next..last)
@@ -1315,7 +1096,7 @@ impl<T: Config> Pallet<T> {
 	fn maturing_referenda_at_inner(
 		n: T::BlockNumber,
 		range: core::ops::Range<PropIndex>,
-	) -> Vec<(ReferendumIndex, ReferendumStatus<T::BlockNumber, T::Hash, BalanceOf<T>>)> {
+	) -> Vec<(ReferendumIndex, ReferendumStatus<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>)> {
 		range
 			.into_iter()
 			.map(|i| (i, Self::referendum_info(i)))
@@ -1331,13 +1112,13 @@ impl<T: Config> Pallet<T> {
 
 	/// Start a referendum.
 	pub fn internal_start_referendum(
-		proposal_hash: T::Hash,
+		proposal: BoundedCallOf<T>,
 		threshold: VoteThreshold,
 		delay: T::BlockNumber,
 	) -> ReferendumIndex {
 		<Pallet<T>>::inject_referendum(
 			<frame_system::Pallet<T>>::block_number().saturating_add(T::VotingPeriod::get()),
-			proposal_hash,
+			proposal,
 			threshold,
 			delay,
 		)
@@ -1353,8 +1134,8 @@ impl<T: Config> Pallet<T> {
 
 	/// Ok if the given referendum is active, Err otherwise
 	fn ensure_ongoing(
-		r: ReferendumInfo<T::BlockNumber, T::Hash, BalanceOf<T>>,
-	) -> Result<ReferendumStatus<T::BlockNumber, T::Hash, BalanceOf<T>>, DispatchError> {
+		r: ReferendumInfo<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>,
+	) -> Result<ReferendumStatus<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>, DispatchError> {
 		match r {
 			ReferendumInfo::Ongoing(s) => Ok(s),
 			_ => Err(Error::<T>::ReferendumInvalid.into()),
@@ -1363,7 +1144,7 @@ impl<T: Config> Pallet<T> {
 
 	fn referendum_status(
 		ref_index: ReferendumIndex,
-	) -> Result<ReferendumStatus<T::BlockNumber, T::Hash, BalanceOf<T>>, DispatchError> {
+	) -> Result<ReferendumStatus<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>, DispatchError> {
 		let info = ReferendumInfoOf::<T>::get(ref_index).ok_or(Error::<T>::ReferendumInvalid)?;
 		Self::ensure_ongoing(info)
 	}
@@ -1388,11 +1169,9 @@ impl<T: Config> Pallet<T> {
 						votes[i].1 = vote;
 					},
 					Err(i) => {
-						ensure!(
-							votes.len() as u32 <= T::MaxVotes::get(),
-							Error::<T>::MaxVotesReached
-						);
-						votes.insert(i, (ref_index, vote));
+						votes
+							.try_insert(i, (ref_index, vote))
+							.map_err(|_| Error::<T>::MaxVotesReached)?;
 					},
 				}
 				Self::deposit_event(Event::<T>::Voted { voter: who.clone(), ref_index, vote });
@@ -1606,14 +1385,14 @@ impl<T: Config> Pallet<T> {
 	/// Start a referendum
 	fn inject_referendum(
 		end: T::BlockNumber,
-		proposal_hash: T::Hash,
+		proposal: BoundedCallOf<T>,
 		threshold: VoteThreshold,
 		delay: T::BlockNumber,
 	) -> ReferendumIndex {
 		let ref_index = Self::referendum_count();
 		ReferendumCount::<T>::put(ref_index + 1);
 		let status =
-			ReferendumStatus { end, proposal_hash, threshold, delay, tally: Default::default() };
+			ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() };
 		let item = ReferendumInfo::Ongoing(status);
 		<ReferendumInfoOf<T>>::insert(ref_index, item);
 		Self::deposit_event(Event::<T>::Started { ref_index, threshold });
@@ -1659,14 +1438,10 @@ impl<T: Config> Pallet<T> {
 
 			if let Some((depositors, deposit)) = <DepositOf<T>>::take(prop_index) {
 				// refund depositors
-				for d in &depositors {
+				for d in depositors.iter() {
 					T::Currency::unreserve(d, deposit);
 				}
-				Self::deposit_event(Event::<T>::Tabled {
-					proposal_index: prop_index,
-					deposit,
-					depositors,
-				});
+				Self::deposit_event(Event::<T>::Tabled { proposal_index: prop_index, deposit });
 				Self::inject_referendum(
 					now.saturating_add(T::VotingPeriod::get()),
 					proposal,
@@ -1680,71 +1455,35 @@ impl<T: Config> Pallet<T> {
 		}
 	}
 
-	fn do_enact_proposal(proposal_hash: T::Hash, index: ReferendumIndex) -> DispatchResult {
-		let preimage = <Preimages<T>>::take(&proposal_hash);
-		if let Some(PreimageStatus::Available { data, provider, deposit, .. }) = preimage {
-			if let Ok(proposal) = T::Proposal::decode(&mut &data[..]) {
-				let err_amount = T::Currency::unreserve(&provider, deposit);
-				debug_assert!(err_amount.is_zero());
-				Self::deposit_event(Event::<T>::PreimageUsed { proposal_hash, provider, deposit });
-
-				let res = proposal
-					.dispatch(frame_system::RawOrigin::Root.into())
-					.map(|_| ())
-					.map_err(|e| e.error);
-				Self::deposit_event(Event::<T>::Executed { ref_index: index, result: res });
-
-				Ok(())
-			} else {
-				T::Slash::on_unbalanced(T::Currency::slash_reserved(&provider, deposit).0);
-				Self::deposit_event(Event::<T>::PreimageInvalid {
-					proposal_hash,
-					ref_index: index,
-				});
-				Err(Error::<T>::PreimageInvalid.into())
-			}
-		} else {
-			Self::deposit_event(Event::<T>::PreimageMissing { proposal_hash, ref_index: index });
-			Err(Error::<T>::PreimageMissing.into())
-		}
-	}
-
 	fn bake_referendum(
 		now: T::BlockNumber,
 		index: ReferendumIndex,
-		status: ReferendumStatus<T::BlockNumber, T::Hash, BalanceOf<T>>,
+		status: ReferendumStatus<T::BlockNumber, BoundedCallOf<T>, BalanceOf<T>>,
 	) -> bool {
 		let total_issuance = T::Currency::total_issuance();
 		let approved = status.threshold.approved(status.tally, total_issuance);
 
 		if approved {
 			Self::deposit_event(Event::<T>::Passed { ref_index: index });
-			if status.delay.is_zero() {
-				let _ = Self::do_enact_proposal(status.proposal_hash, index);
-			} else {
-				let when = now.saturating_add(status.delay);
-				// Note that we need the preimage now.
-				Preimages::<T>::mutate_exists(
-					&status.proposal_hash,
-					|maybe_pre| match *maybe_pre {
-						Some(PreimageStatus::Available { ref mut expiry, .. }) =>
-							*expiry = Some(when),
-						ref mut a => *a = Some(PreimageStatus::Missing(when)),
-					},
-				);
-
-				if T::Scheduler::schedule_named(
-					(DEMOCRACY_ID, index).encode(),
-					DispatchTime::At(when),
-					None,
-					63,
-					frame_system::RawOrigin::Root.into(),
-					Call::enact_proposal { proposal_hash: status.proposal_hash, index }.into(),
-				)
-				.is_err()
-				{
-					frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed");
-				}
+			// Actually `hold` the proposal now since we didn't hold it when it came in via the
+			// submit extrinsic and we now know that it will be needed. This will be reversed by
+			// Scheduler pallet once it is executed which assumes that we will already have placed
+			// a `hold` on it.
+			T::Preimages::hold(&status.proposal);
+
+			// Earliest it can be scheduled for is next block.
+			let when = now.saturating_add(status.delay.max(One::one()));
+			if T::Scheduler::schedule_named(
+				(DEMOCRACY_ID, index).encode_into(),
+				DispatchTime::At(when),
+				None,
+				63,
+				frame_system::RawOrigin::Root.into(),
+				status.proposal,
+			)
+			.is_err()
+			{
+				frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed");
 			}
 		} else {
 			Self::deposit_event(Event::<T>::NotPassed { ref_index: index });
@@ -1780,11 +1519,10 @@ impl<T: Config> Pallet<T> {
 			if Self::launch_next(now).is_ok() {
 				weight = max_block_weight;
 			} else {
-				weight =
-					weight.saturating_add(T::WeightInfo::on_initialize_base_with_launch_period(r));
+				weight.saturating_accrue(T::WeightInfo::on_initialize_base_with_launch_period(r));
 			}
 		} else {
-			weight = weight.saturating_add(T::WeightInfo::on_initialize_base(r));
+			weight.saturating_accrue(T::WeightInfo::on_initialize_base(r));
 		}
 
 		// tally up votes for any expiring referenda.
@@ -1795,8 +1533,8 @@ impl<T: Config> Pallet<T> {
 		}
 
 		// Notes:
-		// * We don't consider the lowest unbaked to be the last maturing in case some refendum have
-		//   longer voting period than others.
+		// * We don't consider the lowest unbaked to be the last maturing in case some referenda
+		//   have a longer voting period than others.
 		// * The iteration here shouldn't trigger any storage read that are not in cache, due to
 		//   `maturing_referenda_at_inner` having already read them.
 		// * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number
@@ -1822,116 +1560,6 @@ impl<T: Config> Pallet<T> {
 		// `Compact<u32>`.
 		decode_compact_u32_at(&<DepositOf<T>>::hashed_key_for(proposal))
 	}
-
-	/// Check that pre image exists and its value is variant `PreimageStatus::Missing`.
-	///
-	/// This check is done without getting the complete value in the runtime to avoid copying a big
-	/// value in the runtime.
-	fn check_pre_image_is_missing(proposal_hash: T::Hash) -> DispatchResult {
-		// To decode the enum variant we only need the first byte.
-		let mut buf = [0u8; 1];
-		let key = <Preimages<T>>::hashed_key_for(proposal_hash);
-		let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::<T>::NotImminent)?;
-		// The value may be smaller that 1 byte.
-		let mut input = &buf[0..buf.len().min(bytes as usize)];
-
-		match input.read_byte() {
-			Ok(0) => Ok(()), // PreimageStatus::Missing is variant 0
-			Ok(1) => Err(Error::<T>::DuplicatePreimage.into()),
-			_ => {
-				sp_runtime::print("Failed to decode `PreimageStatus` variant");
-				Err(Error::<T>::NotImminent.into())
-			},
-		}
-	}
-
-	/// Check that pre image exists, its value is variant `PreimageStatus::Available` and decode
-	/// the length of `data: Vec<u8>` fields.
-	///
-	/// This check is done without getting the complete value in the runtime to avoid copying a big
-	/// value in the runtime.
-	///
-	/// If the pre image is missing variant or doesn't exist then the error `PreimageMissing` is
-	/// returned.
-	fn pre_image_data_len(proposal_hash: T::Hash) -> Result<u32, DispatchError> {
-		// To decode the `data` field of Available variant we need:
-		// * one byte for the variant
-		// * at most 5 bytes to decode a `Compact<u32>`
-		let mut buf = [0u8; 6];
-		let key = <Preimages<T>>::hashed_key_for(proposal_hash);
-		let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::<T>::PreimageMissing)?;
-		// The value may be smaller that 6 bytes.
-		let mut input = &buf[0..buf.len().min(bytes as usize)];
-
-		match input.read_byte() {
-			Ok(1) => (), // Check that input exists and is second variant.
-			Ok(0) => return Err(Error::<T>::PreimageMissing.into()),
-			_ => {
-				sp_runtime::print("Failed to decode `PreimageStatus` variant");
-				return Err(Error::<T>::PreimageMissing.into())
-			},
-		}
-
-		// Decode the length of the vector.
-		let len = codec::Compact::<u32>::decode(&mut input)
-			.map_err(|_| {
-				sp_runtime::print("Failed to decode `PreimageStatus` variant");
-				DispatchError::from(Error::<T>::PreimageMissing)
-			})?
-			.0;
-
-		Ok(len)
-	}
-
-	// See `note_preimage`
-	fn note_preimage_inner(who: T::AccountId, encoded_proposal: Vec<u8>) -> DispatchResult {
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		ensure!(!<Preimages<T>>::contains_key(&proposal_hash), Error::<T>::DuplicatePreimage);
-
-		let deposit = <BalanceOf<T>>::from(encoded_proposal.len() as u32)
-			.saturating_mul(T::PreimageByteDeposit::get());
-		T::Currency::reserve(&who, deposit)?;
-
-		let now = <frame_system::Pallet<T>>::block_number();
-		let a = PreimageStatus::Available {
-			data: encoded_proposal,
-			provider: who.clone(),
-			deposit,
-			since: now,
-			expiry: None,
-		};
-		<Preimages<T>>::insert(proposal_hash, a);
-
-		Self::deposit_event(Event::<T>::PreimageNoted { proposal_hash, who, deposit });
-
-		Ok(())
-	}
-
-	// See `note_imminent_preimage`
-	fn note_imminent_preimage_inner(
-		who: T::AccountId,
-		encoded_proposal: Vec<u8>,
-	) -> DispatchResult {
-		let proposal_hash = T::Hashing::hash(&encoded_proposal[..]);
-		Self::check_pre_image_is_missing(proposal_hash)?;
-		let status = Preimages::<T>::get(&proposal_hash).ok_or(Error::<T>::NotImminent)?;
-		let expiry = status.to_missing_expiry().ok_or(Error::<T>::DuplicatePreimage)?;
-
-		let now = <frame_system::Pallet<T>>::block_number();
-		let free = <BalanceOf<T>>::zero();
-		let a = PreimageStatus::Available {
-			data: encoded_proposal,
-			provider: who.clone(),
-			deposit: Zero::zero(),
-			since: now,
-			expiry: Some(expiry),
-		};
-		<Preimages<T>>::insert(proposal_hash, a);
-
-		Self::deposit_event(Event::<T>::PreimageNoted { proposal_hash, who, deposit: free });
-
-		Ok(())
-	}
 }
 
 /// Decode `Compact<u32>` from the trie at given key.
diff --git a/substrate/frame/democracy/src/migrations.rs b/substrate/frame/democracy/src/migrations.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3ec249c1d981c8d525988d731864de0303ffbc56
--- /dev/null
+++ b/substrate/frame/democracy/src/migrations.rs
@@ -0,0 +1,236 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Storage migrations for the preimage pallet.
+
+use super::*;
+use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec};
+use sp_core::H256;
+
+/// The log target.
+const TARGET: &'static str = "runtime::democracy::migration::v1";
+
+/// The original data layout of the democracy pallet without a specific version number.
+mod v0 {
+	use super::*;
+
+	#[storage_alias]
+	pub type PublicProps<T: Config> = StorageValue<
+		Pallet<T>,
+		Vec<(PropIndex, <T as frame_system::Config>::Hash, <T as frame_system::Config>::AccountId)>,
+		ValueQuery,
+	>;
+
+	#[storage_alias]
+	pub type NextExternal<T: Config> =
+		StorageValue<Pallet<T>, (<T as frame_system::Config>::Hash, VoteThreshold)>;
+
+	#[cfg(feature = "try-runtime")]
+	#[storage_alias]
+	pub type ReferendumInfoOf<T: Config> = StorageMap<
+		Pallet<T>,
+		frame_support::Twox64Concat,
+		ReferendumIndex,
+		ReferendumInfo<
+			<T as frame_system::Config>::BlockNumber,
+			<T as frame_system::Config>::Hash,
+			BalanceOf<T>,
+		>,
+	>;
+}
+
+pub mod v1 {
+	use super::*;
+
+	/// Migration for translating bare `Hash`es into `Bounded<Call>`s.
+	pub struct Migration<T>(sp_std::marker::PhantomData<T>);
+
+	impl<T: Config + frame_system::Config<Hash = H256>> OnRuntimeUpgrade for Migration<T> {
+		#[cfg(feature = "try-runtime")]
+		fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
+
+			let props_count = v0::PublicProps::<T>::get().len();
+			log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,);
+			ensure!(props_count <= T::MaxProposals::get() as usize, "too many proposals");
+
+			let referenda_count = v0::ReferendumInfoOf::<T>::iter().count();
+			log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count);
+
+			Ok((props_count as u32, referenda_count as u32).encode())
+		}
+
+		#[allow(deprecated)]
+		fn on_runtime_upgrade() -> Weight {
+			let mut weight = T::DbWeight::get().reads(1);
+			if StorageVersion::get::<Pallet<T>>() != 0 {
+				log::warn!(
+					target: TARGET,
+					"skipping on_runtime_upgrade: executed on wrong storage version.\
+				Expected version 0"
+				);
+				return weight
+			}
+
+			ReferendumInfoOf::<T>::translate(
+				|index, old: ReferendumInfo<T::BlockNumber, T::Hash, BalanceOf<T>>| {
+					weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
+					log::info!(target: TARGET, "migrating referendum #{:?}", &index);
+					Some(match old {
+						ReferendumInfo::Ongoing(status) =>
+							ReferendumInfo::Ongoing(ReferendumStatus {
+								end: status.end,
+								proposal: Bounded::from_legacy_hash(status.proposal),
+								threshold: status.threshold,
+								delay: status.delay,
+								tally: status.tally,
+							}),
+						ReferendumInfo::Finished { approved, end } =>
+							ReferendumInfo::Finished { approved, end },
+					})
+				},
+			);
+
+			let props = v0::PublicProps::<T>::take()
+				.into_iter()
+				.map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a))
+				.collect::<Vec<_>>();
+			let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone());
+			PublicProps::<T>::put(bounded);
+			weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
+
+			if props.len() as u32 > T::MaxProposals::get() {
+				log::error!(
+					target: TARGET,
+					"truncated {} public proposals to {}; continuing",
+					props.len(),
+					T::MaxProposals::get()
+				);
+			}
+
+			if let Some((hash, threshold)) = v0::NextExternal::<T>::take() {
+				log::info!(target: TARGET, "migrating next external proposal");
+				NextExternal::<T>::put((Bounded::from_legacy_hash(hash), threshold));
+			}
+
+			StorageVersion::new(1).put::<Pallet<T>>();
+
+			weight.saturating_add(T::DbWeight::get().reads_writes(1, 2))
+		}
+
+		#[cfg(feature = "try-runtime")]
+		fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
+
+			let (old_props_count, old_ref_count): (u32, u32) =
+				Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
+			let new_props_count = crate::PublicProps::<T>::get().len() as u32;
+			assert_eq!(new_props_count, old_props_count, "must migrate all public proposals");
+			let new_ref_count = crate::ReferendumInfoOf::<T>::iter().count() as u32;
+			assert_eq!(new_ref_count, old_ref_count, "must migrate all referenda");
+
+			log::info!(
+				target: TARGET,
+				"{} public proposals migrated, {} referenda migrated",
+				new_props_count,
+				new_ref_count,
+			);
+			Ok(())
+		}
+	}
+}
+
+#[cfg(test)]
+#[cfg(feature = "try-runtime")]
+mod test {
+	use super::*;
+	use crate::{
+		tests::{Test as T, *},
+		types::*,
+	};
+	use frame_support::bounded_vec;
+
+	#[allow(deprecated)]
+	#[test]
+	fn migration_works() {
+		new_test_ext().execute_with(|| {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
+			// Insert some values into the v0 storage:
+
+			// Case 1: Ongoing referendum
+			let hash = H256::repeat_byte(1);
+			let status = ReferendumStatus {
+				end: 1u32.into(),
+				proposal: hash.clone(),
+				threshold: VoteThreshold::SuperMajorityApprove,
+				delay: 1u32.into(),
+				tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
+			};
+			v0::ReferendumInfoOf::<T>::insert(1u32, ReferendumInfo::Ongoing(status));
+
+			// Case 2: Finished referendum
+			v0::ReferendumInfoOf::<T>::insert(
+				2u32,
+				ReferendumInfo::Finished { approved: true, end: 123u32.into() },
+			);
+
+			// Case 3: Public proposals
+			let hash2 = H256::repeat_byte(2);
+			v0::PublicProps::<T>::put(vec![
+				(3u32, hash.clone(), 123u64),
+				(4u32, hash2.clone(), 123u64),
+			]);
+
+			// Case 4: Next external
+			v0::NextExternal::<T>::put((hash.clone(), VoteThreshold::SuperMajorityApprove));
+
+			// Migrate.
+			let state = v1::Migration::<T>::pre_upgrade().unwrap();
+			let _weight = v1::Migration::<T>::on_runtime_upgrade();
+			v1::Migration::<T>::post_upgrade(state).unwrap();
+			// Check that all values got migrated.
+
+			// Case 1: Ongoing referendum
+			assert_eq!(
+				ReferendumInfoOf::<T>::get(1u32),
+				Some(ReferendumInfo::Ongoing(ReferendumStatus {
+					end: 1u32.into(),
+					proposal: Bounded::from_legacy_hash(hash),
+					threshold: VoteThreshold::SuperMajorityApprove,
+					delay: 1u32.into(),
+					tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() },
+				}))
+			);
+			// Case 2: Finished referendum
+			assert_eq!(
+				ReferendumInfoOf::<T>::get(2u32),
+				Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() })
+			);
+			// Case 3: Public proposals
+			let props: BoundedVec<_, <Test as Config>::MaxProposals> = bounded_vec![
+				(3u32, Bounded::from_legacy_hash(hash), 123u64),
+				(4u32, Bounded::from_legacy_hash(hash2), 123u64)
+			];
+			assert_eq!(PublicProps::<T>::get(), props);
+			// Case 4: Next external
+			assert_eq!(
+				NextExternal::<T>::get(),
+				Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove))
+			);
+		});
+	}
+}
diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs
index 03d7216fd5aaa38f2cd53c104349d364af3edf43..eceb1a3400bbac97d080322aee8177549ef8e6c6 100644
--- a/substrate/frame/democracy/src/tests.rs
+++ b/substrate/frame/democracy/src/tests.rs
@@ -19,11 +19,11 @@
 
 use super::*;
 use crate as pallet_democracy;
-use codec::Encode;
 use frame_support::{
 	assert_noop, assert_ok, ord_parameter_types, parameter_types,
 	traits::{
-		ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers,
+		ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize,
+		SortedMembers, StorePreimage,
 	},
 	weights::Weight,
 };
@@ -35,14 +35,12 @@ use sp_runtime::{
 	traits::{BadOrigin, BlakeTwo256, IdentityLookup},
 	Perbill,
 };
-
 mod cancellation;
 mod decoders;
 mod delegation;
 mod external_proposing;
 mod fast_tracking;
 mod lock_voting;
-mod preimage;
 mod public_proposals;
 mod scheduling;
 mod voting;
@@ -63,6 +61,7 @@ frame_support::construct_runtime!(
 	{
 		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
 		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
+		Preimage: pallet_preimage,
 		Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>},
 		Democracy: pallet_democracy::{Pallet, Call, Storage, Config<T>, Event<T>},
 	}
@@ -78,13 +77,11 @@ impl Contains<RuntimeCall> for BaseFilter {
 
 parameter_types! {
 	pub BlockWeights: frame_system::limits::BlockWeights =
-		frame_system::limits::BlockWeights::simple_max(
-			Weight::from_ref_time(1_000_000).set_proof_size(u64::MAX),
-		);
+		frame_system::limits::BlockWeights::simple_max(frame_support::weights::constants::WEIGHT_PER_SECOND.set_proof_size(u64::MAX));
 }
 impl frame_system::Config for Test {
 	type BaseCallFilter = BaseFilter;
-	type BlockWeights = ();
+	type BlockWeights = BlockWeights;
 	type BlockLength = ();
 	type DbWeight = ();
 	type RuntimeOrigin = RuntimeOrigin;
@@ -111,6 +108,16 @@ impl frame_system::Config for Test {
 parameter_types! {
 	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;
 }
+
+impl pallet_preimage::Config for Test {
+	type RuntimeEvent = RuntimeEvent;
+	type WeightInfo = ();
+	type Currency = Balances;
+	type ManagerOrigin = EnsureRoot<u64>;
+	type BaseDeposit = ConstU64<0>;
+	type ByteDeposit = ConstU64<0>;
+}
+
 impl pallet_scheduler::Config for Test {
 	type RuntimeEvent = RuntimeEvent;
 	type RuntimeOrigin = RuntimeOrigin;
@@ -118,11 +125,10 @@ impl pallet_scheduler::Config for Test {
 	type RuntimeCall = RuntimeCall;
 	type MaximumWeight = MaximumSchedulerWeight;
 	type ScheduleOrigin = EnsureRoot<u64>;
-	type MaxScheduledPerBlock = ();
+	type MaxScheduledPerBlock = ConstU32<100>;
 	type WeightInfo = ();
 	type OriginPrivilegeCmp = EqualPrivilegeOnly;
-	type PreimageProvider = ();
-	type NoPreimagePostponement = ();
+	type Preimages = ();
 }
 
 impl pallet_balances::Config for Test {
@@ -158,7 +164,6 @@ impl SortedMembers<u64> for OneToFive {
 }
 
 impl Config for Test {
-	type Proposal = RuntimeCall;
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = pallet_balances::Pallet<Self>;
 	type EnactmentPeriod = ConstU64<2>;
@@ -167,6 +172,8 @@ impl Config for Test {
 	type VoteLockingPeriod = ConstU64<3>;
 	type FastTrackVotingPeriod = ConstU64<2>;
 	type MinimumDeposit = ConstU64<1>;
+	type MaxDeposits = ConstU32<1000>;
+	type MaxBlacklisted = ConstU32<5>;
 	type ExternalOrigin = EnsureSignedBy<Two, u64>;
 	type ExternalMajorityOrigin = EnsureSignedBy<Three, u64>;
 	type ExternalDefaultOrigin = EnsureSignedBy<One, u64>;
@@ -176,16 +183,15 @@ impl Config for Test {
 	type CancelProposalOrigin = EnsureRoot<u64>;
 	type VetoOrigin = EnsureSignedBy<OneToFive, u64>;
 	type CooloffPeriod = ConstU64<2>;
-	type PreimageByteDeposit = PreimageByteDeposit;
 	type Slash = ();
 	type InstantOrigin = EnsureSignedBy<Six, u64>;
 	type InstantAllowed = InstantAllowed;
 	type Scheduler = Scheduler;
 	type MaxVotes = ConstU32<100>;
-	type OperationalPreimageOrigin = EnsureSignedBy<Six, u64>;
 	type PalletsOrigin = OriginCaller;
 	type WeightInfo = ();
 	type MaxProposals = ConstU32<100>;
+	type Preimages = Preimage;
 }
 
 pub fn new_test_ext() -> sp_io::TestExternalities {
@@ -203,12 +209,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
 	ext
 }
 
-/// Execute the function two times, with `true` and with `false`.
-pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) {
-	new_test_ext().execute_with(|| (execute.clone())(false));
-	new_test_ext().execute_with(|| execute(true));
-}
-
 #[test]
 fn params_should_work() {
 	new_test_ext().execute_with(|| {
@@ -218,44 +218,22 @@ fn params_should_work() {
 	});
 }
 
-fn set_balance_proposal(value: u64) -> Vec<u8> {
-	RuntimeCall::Balances(pallet_balances::Call::set_balance {
-		who: 42,
-		new_free: value,
-		new_reserved: 0,
-	})
-	.encode()
+fn set_balance_proposal(value: u64) -> BoundedCallOf<Test> {
+	let inner = pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 };
+	let outer = RuntimeCall::Balances(inner);
+	Preimage::bound(outer).unwrap()
 }
 
 #[test]
 fn set_balance_proposal_is_correctly_filtered_out() {
 	for i in 0..10 {
-		let call = RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap();
+		let call = Preimage::realize(&set_balance_proposal(i)).unwrap().0;
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
 	}
 }
 
-fn set_balance_proposal_hash(value: u64) -> H256 {
-	BlakeTwo256::hash(&set_balance_proposal(value)[..])
-}
-
-fn set_balance_proposal_hash_and_note(value: u64) -> H256 {
-	let p = set_balance_proposal(value);
-	let h = BlakeTwo256::hash(&p[..]);
-	match Democracy::note_preimage(RuntimeOrigin::signed(6), p) {
-		Ok(_) => (),
-		Err(x) if x == Error::<Test>::DuplicatePreimage.into() => (),
-		Err(x) => panic!("{:?}", x),
-	}
-	h
-}
-
 fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult {
-	Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash(value), delay)
-}
-
-fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchResult {
-	Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal_hash_and_note(value), delay)
+	Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal(value), delay)
 }
 
 fn next_block() {
@@ -272,7 +250,7 @@ fn fast_forward_to(n: u64) {
 
 fn begin_referendum() -> ReferendumIndex {
 	System::set_block_number(0);
-	assert_ok!(propose_set_balance_and_note(1, 2, 1));
+	assert_ok!(propose_set_balance(1, 2, 1));
 	fast_forward_to(2);
 	0
 }
diff --git a/substrate/frame/democracy/src/tests/cancellation.rs b/substrate/frame/democracy/src/tests/cancellation.rs
index b98e51aa3d4d1e30c97727762abe6e2484f78fce..ff046d612c026f2b95068e17df9e588e1f122193 100644
--- a/substrate/frame/democracy/src/tests/cancellation.rs
+++ b/substrate/frame/democracy/src/tests/cancellation.rs
@@ -24,7 +24,7 @@ fn cancel_referendum_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -42,37 +42,13 @@ fn cancel_referendum_should_work() {
 	});
 }
 
-#[test]
-fn cancel_queued_should_work() {
-	new_test_ext().execute_with(|| {
-		System::set_block_number(0);
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
-
-		// start of 2 => next referendum scheduled.
-		fast_forward_to(2);
-
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
-
-		fast_forward_to(4);
-
-		assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_some());
-
-		assert_noop!(
-			Democracy::cancel_queued(RuntimeOrigin::root(), 1),
-			Error::<Test>::ProposalMissing
-		);
-		assert_ok!(Democracy::cancel_queued(RuntimeOrigin::root(), 0));
-		assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_none());
-	});
-}
-
 #[test]
 fn emergency_cancel_should_work() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			2,
 		);
@@ -86,7 +62,7 @@ fn emergency_cancel_should_work() {
 
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			2,
 		);
diff --git a/substrate/frame/democracy/src/tests/decoders.rs b/substrate/frame/democracy/src/tests/decoders.rs
index 1fbb88060549b90038e1a5cbb2a1471975e20a86..1c8b9c3d980f9002606cc8d513a7ea4b54d2d443 100644
--- a/substrate/frame/democracy/src/tests/decoders.rs
+++ b/substrate/frame/democracy/src/tests/decoders.rs
@@ -18,7 +18,10 @@
 //! The for various partial storage decoders
 
 use super::*;
-use frame_support::storage::{migration, unhashed};
+use frame_support::{
+	storage::{migration, unhashed},
+	BoundedVec,
+};
 
 #[test]
 fn test_decode_compact_u32_at() {
@@ -42,7 +45,8 @@ fn test_decode_compact_u32_at() {
 fn len_of_deposit_of() {
 	new_test_ext().execute_with(|| {
 		for l in vec![0, 1, 200, 1000] {
-			let value: (Vec<u64>, u64) = ((0..l).map(|_| Default::default()).collect(), 3u64);
+			let value: (BoundedVec<u64, _>, u64) =
+				((0..l).map(|_| Default::default()).collect::<Vec<_>>().try_into().unwrap(), 3u64);
 			DepositOf::<Test>::insert(2, value);
 			assert_eq!(Democracy::len_of_deposit_of(2), Some(l));
 		}
@@ -51,35 +55,3 @@ fn len_of_deposit_of() {
 		assert_eq!(Democracy::len_of_deposit_of(2), None);
 	})
 }
-
-#[test]
-fn pre_image() {
-	new_test_ext().execute_with(|| {
-		let key = Default::default();
-		let missing = PreimageStatus::Missing(0);
-		Preimages::<Test>::insert(key, missing);
-		assert_noop!(Democracy::pre_image_data_len(key), Error::<Test>::PreimageMissing);
-		assert_eq!(Democracy::check_pre_image_is_missing(key), Ok(()));
-
-		Preimages::<Test>::remove(key);
-		assert_noop!(Democracy::pre_image_data_len(key), Error::<Test>::PreimageMissing);
-		assert_noop!(Democracy::check_pre_image_is_missing(key), Error::<Test>::NotImminent);
-
-		for l in vec![0, 10, 100, 1000u32] {
-			let available = PreimageStatus::Available {
-				data: (0..l).map(|i| i as u8).collect(),
-				provider: 0,
-				deposit: 0,
-				since: 0,
-				expiry: None,
-			};
-
-			Preimages::<Test>::insert(key, available);
-			assert_eq!(Democracy::pre_image_data_len(key), Ok(l));
-			assert_noop!(
-				Democracy::check_pre_image_is_missing(key),
-				Error::<Test>::DuplicatePreimage
-			);
-		}
-	})
-}
diff --git a/substrate/frame/democracy/src/tests/delegation.rs b/substrate/frame/democracy/src/tests/delegation.rs
index 4c5ee792860556fac6b2eabaee1fe375dbfe315f..bca7cb95241120d0311ccebde29d1dab4ee0d93c 100644
--- a/substrate/frame/democracy/src/tests/delegation.rs
+++ b/substrate/frame/democracy/src/tests/delegation.rs
@@ -24,7 +24,7 @@ fn single_proposal_should_work_with_delegation() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
+		assert_ok!(propose_set_balance(1, 2, 1));
 
 		fast_forward_to(2);
 
@@ -75,7 +75,7 @@ fn cyclic_delegation_should_unwind() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
+		assert_ok!(propose_set_balance(1, 2, 1));
 
 		fast_forward_to(2);
 
@@ -100,7 +100,7 @@ fn single_proposal_should_work_with_vote_and_delegation() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
+		assert_ok!(propose_set_balance(1, 2, 1));
 
 		fast_forward_to(2);
 
@@ -122,7 +122,7 @@ fn single_proposal_should_work_with_undelegation() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
+		assert_ok!(propose_set_balance(1, 2, 1));
 
 		// Delegate and undelegate vote.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
diff --git a/substrate/frame/democracy/src/tests/external_proposing.rs b/substrate/frame/democracy/src/tests/external_proposing.rs
index fda555b9c345999bd0255523f5da545c54031a6f..4cfdd2aa74a3d4e1a884dbff7be7aea1eb6f0661 100644
--- a/substrate/frame/democracy/src/tests/external_proposing.rs
+++ b/substrate/frame/democracy/src/tests/external_proposing.rs
@@ -23,35 +23,29 @@ use super::*;
 fn veto_external_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(2),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
 		assert!(<NextExternal<Test>>::exists());
 
-		let h = set_balance_proposal_hash_and_note(2);
+		let h = set_balance_proposal(2).hash();
 		assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h));
 		// cancelled.
 		assert!(!<NextExternal<Test>>::exists());
 		// fails - same proposal can't be resubmitted.
 		assert_noop!(
-			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
+			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),),
 			Error::<Test>::ProposalBlacklisted
 		);
 
 		fast_forward_to(1);
 		// fails as we're still in cooloff period.
 		assert_noop!(
-			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
+			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),),
 			Error::<Test>::ProposalBlacklisted
 		);
 
 		fast_forward_to(2);
 		// works; as we're out of the cooloff period.
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(2),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
 		assert!(<NextExternal<Test>>::exists());
 
 		// 3 can't veto the same thing twice.
@@ -68,14 +62,11 @@ fn veto_external_works() {
 		fast_forward_to(3);
 		// same proposal fails as we're still in cooloff
 		assert_noop!(
-			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(2),),
+			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)),
 			Error::<Test>::ProposalBlacklisted
 		);
 		// different proposal works fine.
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(3),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),));
 	});
 }
 
@@ -84,22 +75,16 @@ fn external_blacklisting_should_work() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(2),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
 
-		let hash = set_balance_proposal_hash(2);
+		let hash = set_balance_proposal(2).hash();
 		assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));
 
 		fast_forward_to(2);
 		assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
 
 		assert_noop!(
-			Democracy::external_propose(
-				RuntimeOrigin::signed(2),
-				set_balance_proposal_hash_and_note(2),
-			),
+			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)),
 			Error::<Test>::ProposalBlacklisted,
 		);
 	});
@@ -110,15 +95,12 @@ fn external_referendum_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 		assert_noop!(
-			Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal_hash(2),),
+			Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal(2),),
 			BadOrigin,
 		);
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(2),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),));
 		assert_noop!(
-			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal_hash(1),),
+			Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),),
 			Error::<Test>::DuplicateProposal
 		);
 		fast_forward_to(2);
@@ -126,7 +108,7 @@ fn external_referendum_works() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 4,
-				proposal_hash: set_balance_proposal_hash(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -140,22 +122,19 @@ fn external_majority_referendum_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 		assert_noop!(
-			Democracy::external_propose_majority(
-				RuntimeOrigin::signed(1),
-				set_balance_proposal_hash(2)
-			),
+			Democracy::external_propose_majority(RuntimeOrigin::signed(1), set_balance_proposal(2)),
 			BadOrigin,
 		);
 		assert_ok!(Democracy::external_propose_majority(
 			RuntimeOrigin::signed(3),
-			set_balance_proposal_hash_and_note(2)
+			set_balance_proposal(2)
 		));
 		fast_forward_to(2);
 		assert_eq!(
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 4,
-				proposal_hash: set_balance_proposal_hash(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SimpleMajority,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -169,22 +148,19 @@ fn external_default_referendum_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
 		assert_noop!(
-			Democracy::external_propose_default(
-				RuntimeOrigin::signed(3),
-				set_balance_proposal_hash(2)
-			),
+			Democracy::external_propose_default(RuntimeOrigin::signed(3), set_balance_proposal(2)),
 			BadOrigin,
 		);
 		assert_ok!(Democracy::external_propose_default(
 			RuntimeOrigin::signed(1),
-			set_balance_proposal_hash_and_note(2)
+			set_balance_proposal(2)
 		));
 		fast_forward_to(2);
 		assert_eq!(
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 4,
-				proposal_hash: set_balance_proposal_hash(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SuperMajorityAgainst,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -197,11 +173,8 @@ fn external_default_referendum_works() {
 fn external_and_public_interleaving_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(1),
-		));
-		assert_ok!(propose_set_balance_and_note(6, 2, 2));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),));
+		assert_ok!(propose_set_balance(6, 2, 2));
 
 		fast_forward_to(2);
 
@@ -210,17 +183,14 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 4,
-				proposal_hash: set_balance_proposal_hash_and_note(1),
+				proposal: set_balance_proposal(1),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
 			})
 		);
 		// replenish external
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(3),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),));
 
 		fast_forward_to(4);
 
@@ -229,7 +199,7 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(1),
 			Ok(ReferendumStatus {
 				end: 6,
-				proposal_hash: set_balance_proposal_hash_and_note(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -244,17 +214,14 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(2),
 			Ok(ReferendumStatus {
 				end: 8,
-				proposal_hash: set_balance_proposal_hash_and_note(3),
+				proposal: set_balance_proposal(3),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
 			})
 		);
 		// replenish external
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(5),
-		));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(5),));
 
 		fast_forward_to(8);
 
@@ -263,18 +230,15 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(3),
 			Ok(ReferendumStatus {
 				end: 10,
-				proposal_hash: set_balance_proposal_hash_and_note(5),
+				proposal: set_balance_proposal(5),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
 			})
 		);
 		// replenish both
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(7),
-		));
-		assert_ok!(propose_set_balance_and_note(6, 4, 2));
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(7),));
+		assert_ok!(propose_set_balance(6, 4, 2));
 
 		fast_forward_to(10);
 
@@ -283,16 +247,16 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(4),
 			Ok(ReferendumStatus {
 				end: 12,
-				proposal_hash: set_balance_proposal_hash_and_note(4),
+				proposal: set_balance_proposal(4),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
 			})
 		);
 		// replenish public again
-		assert_ok!(propose_set_balance_and_note(6, 6, 2));
+		assert_ok!(propose_set_balance(6, 6, 2));
 		// cancel external
-		let h = set_balance_proposal_hash_and_note(7);
+		let h = set_balance_proposal(7).hash();
 		assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h));
 
 		fast_forward_to(12);
@@ -302,7 +266,7 @@ fn external_and_public_interleaving_works() {
 			Democracy::referendum_status(5),
 			Ok(ReferendumStatus {
 				end: 14,
-				proposal_hash: set_balance_proposal_hash_and_note(6),
+				proposal: set_balance_proposal(6),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
diff --git a/substrate/frame/democracy/src/tests/fast_tracking.rs b/substrate/frame/democracy/src/tests/fast_tracking.rs
index 8fef985c8561c30fbb8ad94b6e8671b2beaeb6f0..97bb7a63908ab2249872c280f7e3d4e939bbdada 100644
--- a/substrate/frame/democracy/src/tests/fast_tracking.rs
+++ b/substrate/frame/democracy/src/tests/fast_tracking.rs
@@ -23,14 +23,14 @@ use super::*;
 fn fast_track_referendum_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		let h = set_balance_proposal_hash_and_note(2);
+		let h = set_balance_proposal(2).hash();
 		assert_noop!(
 			Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
 			Error::<Test>::ProposalMissing
 		);
 		assert_ok!(Democracy::external_propose_majority(
 			RuntimeOrigin::signed(3),
-			set_balance_proposal_hash_and_note(2)
+			set_balance_proposal(2)
 		));
 		assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin);
 		assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0));
@@ -38,7 +38,7 @@ fn fast_track_referendum_works() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 2,
-				proposal_hash: set_balance_proposal_hash_and_note(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SimpleMajority,
 				delay: 0,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -51,14 +51,14 @@ fn fast_track_referendum_works() {
 fn instant_referendum_works() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		let h = set_balance_proposal_hash_and_note(2);
+		let h = set_balance_proposal(2).hash();
 		assert_noop!(
 			Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
 			Error::<Test>::ProposalMissing
 		);
 		assert_ok!(Democracy::external_propose_majority(
 			RuntimeOrigin::signed(3),
-			set_balance_proposal_hash_and_note(2)
+			set_balance_proposal(2)
 		));
 		assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin);
 		assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 1, 0), BadOrigin);
@@ -76,7 +76,7 @@ fn instant_referendum_works() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 1,
-				proposal_hash: set_balance_proposal_hash_and_note(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SimpleMajority,
 				delay: 0,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -93,7 +93,7 @@ fn instant_next_block_referendum_backed() {
 		let majority_origin_id = 3;
 		let instant_origin_id = 6;
 		let voting_period = 1;
-		let proposal_hash = set_balance_proposal_hash_and_note(2);
+		let proposal = set_balance_proposal(2);
 		let delay = 2; // has no effect on test
 
 		// init
@@ -103,13 +103,13 @@ fn instant_next_block_referendum_backed() {
 		// propose with majority origin
 		assert_ok!(Democracy::external_propose_majority(
 			RuntimeOrigin::signed(majority_origin_id),
-			proposal_hash
+			proposal.clone()
 		));
 
 		// fast track with instant origin and voting period pointing to the next block
 		assert_ok!(Democracy::fast_track(
 			RuntimeOrigin::signed(instant_origin_id),
-			proposal_hash,
+			proposal.hash(),
 			voting_period,
 			delay
 		));
@@ -119,7 +119,7 @@ fn instant_next_block_referendum_backed() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: start_block_number + voting_period,
-				proposal_hash,
+				proposal,
 				threshold: VoteThreshold::SimpleMajority,
 				delay,
 				tally: Tally { ayes: 0, nays: 0, turnout: 0 },
@@ -143,11 +143,8 @@ fn instant_next_block_referendum_backed() {
 fn fast_track_referendum_fails_when_no_simple_majority() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		let h = set_balance_proposal_hash_and_note(2);
-		assert_ok!(Democracy::external_propose(
-			RuntimeOrigin::signed(2),
-			set_balance_proposal_hash_and_note(2)
-		));
+		let h = set_balance_proposal(2).hash();
+		assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)));
 		assert_noop!(
 			Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2),
 			Error::<Test>::NotSimpleMajority
diff --git a/substrate/frame/democracy/src/tests/lock_voting.rs b/substrate/frame/democracy/src/tests/lock_voting.rs
index de1137f03fd3838a48f93e3af603c90fe39d0d20..540198ecf33a166debe021825070852fa9427231 100644
--- a/substrate/frame/democracy/src/tests/lock_voting.rs
+++ b/substrate/frame/democracy/src/tests/lock_voting.rs
@@ -43,7 +43,7 @@ fn lock_voting_should_work() {
 		System::set_block_number(0);
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -59,7 +59,7 @@ fn lock_voting_should_work() {
 			assert_eq!(Balances::locks(i), vec![the_lock(i * 10)]);
 		}
 
-		fast_forward_to(2);
+		fast_forward_to(3);
 
 		// Referendum passed; 1 and 5 didn't get their way and can now reap and unlock.
 		assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r));
@@ -126,13 +126,13 @@ fn no_locks_without_conviction_should_work() {
 		System::set_block_number(0);
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(0, 10)));
 
-		fast_forward_to(2);
+		fast_forward_to(3);
 
 		assert_eq!(Balances::free_balance(42), 2);
 		assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 1, r));
@@ -146,7 +146,7 @@ fn lock_voting_should_work_with_delegation() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -167,28 +167,16 @@ fn lock_voting_should_work_with_delegation() {
 
 fn setup_three_referenda() -> (u32, u32, u32) {
 	System::set_block_number(0);
-	let r1 = Democracy::inject_referendum(
-		2,
-		set_balance_proposal_hash_and_note(2),
-		VoteThreshold::SimpleMajority,
-		0,
-	);
+	let r1 =
+		Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
 	assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r1, aye(4, 10)));
 
-	let r2 = Democracy::inject_referendum(
-		2,
-		set_balance_proposal_hash_and_note(2),
-		VoteThreshold::SimpleMajority,
-		0,
-	);
+	let r2 =
+		Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
 	assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r2, aye(3, 20)));
 
-	let r3 = Democracy::inject_referendum(
-		2,
-		set_balance_proposal_hash_and_note(2),
-		VoteThreshold::SimpleMajority,
-		0,
-	);
+	let r3 =
+		Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0);
 	assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r3, aye(2, 50)));
 
 	fast_forward_to(2);
@@ -306,7 +294,7 @@ fn locks_should_persist_from_voting_to_delegation() {
 		System::set_block_number(0);
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SimpleMajority,
 			0,
 		);
diff --git a/substrate/frame/democracy/src/tests/preimage.rs b/substrate/frame/democracy/src/tests/preimage.rs
deleted file mode 100644
index 39536eab8009bfabc76a31ed112863b412c5bbd5..0000000000000000000000000000000000000000
--- a/substrate/frame/democracy/src/tests/preimage.rs
+++ /dev/null
@@ -1,237 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// 	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! The preimage tests.
-
-use super::*;
-
-#[test]
-fn missing_preimage_should_fail() {
-	new_test_ext().execute_with(|| {
-		let r = Democracy::inject_referendum(
-			2,
-			set_balance_proposal_hash(2),
-			VoteThreshold::SuperMajorityApprove,
-			0,
-		);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-
-		next_block();
-		next_block();
-
-		assert_eq!(Balances::free_balance(42), 0);
-	});
-}
-
-#[test]
-fn preimage_deposit_should_be_required_and_returned() {
-	new_test_ext_execute_with_cond(|operational| {
-		// fee of 100 is too much.
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 100);
-		assert_noop!(
-			if operational {
-				Democracy::note_preimage_operational(RuntimeOrigin::signed(6), vec![0; 500])
-			} else {
-				Democracy::note_preimage(RuntimeOrigin::signed(6), vec![0; 500])
-			},
-			BalancesError::<Test, _>::InsufficientBalance,
-		);
-		// fee of 1 is reasonable.
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
-		let r = Democracy::inject_referendum(
-			2,
-			set_balance_proposal_hash_and_note(2),
-			VoteThreshold::SuperMajorityApprove,
-			0,
-		);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-
-		assert_eq!(Balances::reserved_balance(6), 12);
-
-		next_block();
-		next_block();
-
-		assert_eq!(Balances::reserved_balance(6), 0);
-		assert_eq!(Balances::free_balance(6), 60);
-		assert_eq!(Balances::free_balance(42), 2);
-	});
-}
-
-#[test]
-fn preimage_deposit_should_be_reapable_earlier_by_owner() {
-	new_test_ext_execute_with_cond(|operational| {
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
-		assert_ok!(if operational {
-			Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2))
-		} else {
-			Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
-		});
-
-		assert_eq!(Balances::reserved_balance(6), 12);
-
-		next_block();
-		assert_noop!(
-			Democracy::reap_preimage(
-				RuntimeOrigin::signed(6),
-				set_balance_proposal_hash(2),
-				u32::MAX
-			),
-			Error::<Test>::TooEarly
-		);
-		next_block();
-		assert_ok!(Democracy::reap_preimage(
-			RuntimeOrigin::signed(6),
-			set_balance_proposal_hash(2),
-			u32::MAX
-		));
-
-		assert_eq!(Balances::free_balance(6), 60);
-		assert_eq!(Balances::reserved_balance(6), 0);
-	});
-}
-
-#[test]
-fn preimage_deposit_should_be_reapable() {
-	new_test_ext_execute_with_cond(|operational| {
-		assert_noop!(
-			Democracy::reap_preimage(
-				RuntimeOrigin::signed(5),
-				set_balance_proposal_hash(2),
-				u32::MAX
-			),
-			Error::<Test>::PreimageMissing
-		);
-
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
-		assert_ok!(if operational {
-			Democracy::note_preimage_operational(RuntimeOrigin::signed(6), set_balance_proposal(2))
-		} else {
-			Democracy::note_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
-		});
-		assert_eq!(Balances::reserved_balance(6), 12);
-
-		next_block();
-		next_block();
-		next_block();
-		assert_noop!(
-			Democracy::reap_preimage(
-				RuntimeOrigin::signed(5),
-				set_balance_proposal_hash(2),
-				u32::MAX
-			),
-			Error::<Test>::TooEarly
-		);
-
-		next_block();
-		assert_ok!(Democracy::reap_preimage(
-			RuntimeOrigin::signed(5),
-			set_balance_proposal_hash(2),
-			u32::MAX
-		));
-		assert_eq!(Balances::reserved_balance(6), 0);
-		assert_eq!(Balances::free_balance(6), 48);
-		assert_eq!(Balances::free_balance(5), 62);
-	});
-}
-
-#[test]
-fn noting_imminent_preimage_for_free_should_work() {
-	new_test_ext_execute_with_cond(|operational| {
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
-
-		let r = Democracy::inject_referendum(
-			2,
-			set_balance_proposal_hash(2),
-			VoteThreshold::SuperMajorityApprove,
-			1,
-		);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-
-		assert_noop!(
-			if operational {
-				Democracy::note_imminent_preimage_operational(
-					RuntimeOrigin::signed(6),
-					set_balance_proposal(2),
-				)
-			} else {
-				Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2))
-			},
-			Error::<Test>::NotImminent
-		);
-
-		next_block();
-
-		// Now we're in the dispatch queue it's all good.
-		assert_ok!(Democracy::note_imminent_preimage(
-			RuntimeOrigin::signed(6),
-			set_balance_proposal(2)
-		));
-
-		next_block();
-
-		assert_eq!(Balances::free_balance(42), 2);
-	});
-}
-
-#[test]
-fn reaping_imminent_preimage_should_fail() {
-	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash_and_note(2);
-		let r = Democracy::inject_referendum(3, h, VoteThreshold::SuperMajorityApprove, 1);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		next_block();
-		next_block();
-		assert_noop!(
-			Democracy::reap_preimage(RuntimeOrigin::signed(6), h, u32::MAX),
-			Error::<Test>::Imminent
-		);
-	});
-}
-
-#[test]
-fn note_imminent_preimage_can_only_be_successful_once() {
-	new_test_ext().execute_with(|| {
-		PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1);
-
-		let r = Democracy::inject_referendum(
-			2,
-			set_balance_proposal_hash(2),
-			VoteThreshold::SuperMajorityApprove,
-			1,
-		);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		next_block();
-
-		// First time works
-		assert_ok!(Democracy::note_imminent_preimage(
-			RuntimeOrigin::signed(6),
-			set_balance_proposal(2)
-		));
-
-		// Second time fails
-		assert_noop!(
-			Democracy::note_imminent_preimage(RuntimeOrigin::signed(6), set_balance_proposal(2)),
-			Error::<Test>::DuplicatePreimage
-		);
-
-		// Fails from any user
-		assert_noop!(
-			Democracy::note_imminent_preimage(RuntimeOrigin::signed(5), set_balance_proposal(2)),
-			Error::<Test>::DuplicatePreimage
-		);
-	});
-}
diff --git a/substrate/frame/democracy/src/tests/public_proposals.rs b/substrate/frame/democracy/src/tests/public_proposals.rs
index c52533e46ccc576d298112c6a9087ba688634ed9..f48824dc95c5d84b6e59de5757730fb23d3e4564 100644
--- a/substrate/frame/democracy/src/tests/public_proposals.rs
+++ b/substrate/frame/democracy/src/tests/public_proposals.rs
@@ -22,9 +22,9 @@ use super::*;
 #[test]
 fn backing_for_should_work() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(1, 2, 2));
-		assert_ok!(propose_set_balance_and_note(1, 4, 4));
-		assert_ok!(propose_set_balance_and_note(1, 3, 3));
+		assert_ok!(propose_set_balance(1, 2, 2));
+		assert_ok!(propose_set_balance(1, 4, 4));
+		assert_ok!(propose_set_balance(1, 3, 3));
 		assert_eq!(Democracy::backing_for(0), Some(2));
 		assert_eq!(Democracy::backing_for(1), Some(4));
 		assert_eq!(Democracy::backing_for(2), Some(3));
@@ -34,11 +34,11 @@ fn backing_for_should_work() {
 #[test]
 fn deposit_for_proposals_should_be_taken() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(1, 2, 5));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
+		assert_ok!(propose_set_balance(1, 2, 5));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		assert_eq!(Balances::free_balance(1), 5);
 		assert_eq!(Balances::free_balance(2), 15);
 		assert_eq!(Balances::free_balance(5), 35);
@@ -48,11 +48,11 @@ fn deposit_for_proposals_should_be_taken() {
 #[test]
 fn deposit_for_proposals_should_be_returned() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(1, 2, 5));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
-		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0, u32::MAX));
+		assert_ok!(propose_set_balance(1, 2, 5));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
+		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		fast_forward_to(3);
 		assert_eq!(Balances::free_balance(1), 10);
 		assert_eq!(Balances::free_balance(2), 20);
@@ -77,30 +77,19 @@ fn poor_proposer_should_not_work() {
 #[test]
 fn poor_seconder_should_not_work() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(2, 2, 11));
+		assert_ok!(propose_set_balance(2, 2, 11));
 		assert_noop!(
-			Democracy::second(RuntimeOrigin::signed(1), 0, u32::MAX),
+			Democracy::second(RuntimeOrigin::signed(1), 0),
 			BalancesError::<Test, _>::InsufficientBalance
 		);
 	});
 }
 
-#[test]
-fn invalid_seconds_upper_bound_should_not_work() {
-	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(1, 2, 5));
-		assert_noop!(
-			Democracy::second(RuntimeOrigin::signed(2), 0, 0),
-			Error::<Test>::WrongUpperBound
-		);
-	});
-}
-
 #[test]
 fn cancel_proposal_should_work() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance_and_note(1, 2, 2));
-		assert_ok!(propose_set_balance_and_note(1, 4, 4));
+		assert_ok!(propose_set_balance(1, 2, 2));
+		assert_ok!(propose_set_balance(1, 4, 4));
 		assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin);
 		assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0));
 		System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into());
@@ -113,10 +102,10 @@ fn cancel_proposal_should_work() {
 fn blacklisting_should_work() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		let hash = set_balance_proposal_hash(2);
+		let hash = set_balance_proposal(2).hash();
 
-		assert_ok!(propose_set_balance_and_note(1, 2, 2));
-		assert_ok!(propose_set_balance_and_note(1, 4, 4));
+		assert_ok!(propose_set_balance(1, 2, 2));
+		assert_ok!(propose_set_balance(1, 4, 4));
 
 		assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin);
 		assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));
@@ -124,11 +113,11 @@ fn blacklisting_should_work() {
 		assert_eq!(Democracy::backing_for(0), None);
 		assert_eq!(Democracy::backing_for(1), Some(4));
 
-		assert_noop!(propose_set_balance_and_note(1, 2, 2), Error::<Test>::ProposalBlacklisted);
+		assert_noop!(propose_set_balance(1, 2, 2), Error::<Test>::ProposalBlacklisted);
 
 		fast_forward_to(2);
 
-		let hash = set_balance_proposal_hash(4);
+		let hash = set_balance_proposal(4).hash();
 		assert_ok!(Democracy::referendum_status(0));
 		assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, Some(0)));
 		assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
@@ -139,9 +128,9 @@ fn blacklisting_should_work() {
 fn runners_up_should_come_after() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_ok!(propose_set_balance_and_note(1, 2, 2));
-		assert_ok!(propose_set_balance_and_note(1, 4, 4));
-		assert_ok!(propose_set_balance_and_note(1, 3, 3));
+		assert_ok!(propose_set_balance(1, 2, 2));
+		assert_ok!(propose_set_balance(1, 4, 4));
+		assert_ok!(propose_set_balance(1, 3, 3));
 		fast_forward_to(2);
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
 		fast_forward_to(4);
diff --git a/substrate/frame/democracy/src/tests/scheduling.rs b/substrate/frame/democracy/src/tests/scheduling.rs
index 4b5fe8dd9c1c3d94ded21d762ef0272b3654ec43..5e133f38945d6c8e3968f2f05ab18e93ed858b69 100644
--- a/substrate/frame/democracy/src/tests/scheduling.rs
+++ b/substrate/frame/democracy/src/tests/scheduling.rs
@@ -24,7 +24,7 @@ fn simple_passing_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -43,7 +43,7 @@ fn simple_failing_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -62,13 +62,13 @@ fn ooo_inject_referendums_should_work() {
 	new_test_ext().execute_with(|| {
 		let r1 = Democracy::inject_referendum(
 			3,
-			set_balance_proposal_hash_and_note(3),
+			set_balance_proposal(3),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
 		let r2 = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -77,11 +77,13 @@ fn ooo_inject_referendums_should_work() {
 		assert_eq!(tally(r2), Tally { ayes: 1, nays: 0, turnout: 10 });
 
 		next_block();
-		assert_eq!(Balances::free_balance(42), 2);
 
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1)));
 		assert_eq!(tally(r1), Tally { ayes: 1, nays: 0, turnout: 10 });
 
+		next_block();
+		assert_eq!(Balances::free_balance(42), 2);
+
 		next_block();
 		assert_eq!(Balances::free_balance(42), 3);
 	});
@@ -92,7 +94,7 @@ fn delayed_enactment_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			1,
 		);
@@ -118,19 +120,19 @@ fn lowest_unbaked_should_be_sensible() {
 	new_test_ext().execute_with(|| {
 		let r1 = Democracy::inject_referendum(
 			3,
-			set_balance_proposal_hash_and_note(1),
+			set_balance_proposal(1),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
 		let r2 = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
 		let r3 = Democracy::inject_referendum(
 			10,
-			set_balance_proposal_hash_and_note(3),
+			set_balance_proposal(3),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -141,16 +143,19 @@ fn lowest_unbaked_should_be_sensible() {
 		assert_eq!(Democracy::lowest_unbaked(), 0);
 
 		next_block();
-
-		// r2 is approved
-		assert_eq!(Balances::free_balance(42), 2);
+		// r2 ends with approval
 		assert_eq!(Democracy::lowest_unbaked(), 0);
 
 		next_block();
-
-		// r1 is approved
-		assert_eq!(Balances::free_balance(42), 1);
+		// r1 ends with approval
 		assert_eq!(Democracy::lowest_unbaked(), 3);
 		assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count());
+
+		// r2 is executed
+		assert_eq!(Balances::free_balance(42), 2);
+
+		next_block();
+		// r1 is executed
+		assert_eq!(Balances::free_balance(42), 1);
 	});
 }
diff --git a/substrate/frame/democracy/src/tests/voting.rs b/substrate/frame/democracy/src/tests/voting.rs
index 59d0cd6bc50efd0449318971a3f0e8f4be71024f..482cd430e0e7f1a907e884aa23eb15c2ce13d9f2 100644
--- a/substrate/frame/democracy/src/tests/voting.rs
+++ b/substrate/frame/democracy/src/tests/voting.rs
@@ -63,7 +63,7 @@ fn split_vote_cancellation_should_work() {
 fn single_proposal_should_work() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_ok!(propose_set_balance_and_note(1, 2, 1));
+		assert_ok!(propose_set_balance(1, 2, 1));
 		let r = 0;
 		assert!(Democracy::referendum_info(r).is_none());
 
@@ -76,7 +76,7 @@ fn single_proposal_should_work() {
 			Democracy::referendum_status(0),
 			Ok(ReferendumStatus {
 				end: 4,
-				proposal_hash: set_balance_proposal_hash_and_note(2),
+				proposal: set_balance_proposal(2),
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
 				tally: Tally { ayes: 1, nays: 0, turnout: 10 },
@@ -106,7 +106,7 @@ fn controversial_voting_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -132,7 +132,7 @@ fn controversial_low_turnout_voting_should_work() {
 	new_test_ext().execute_with(|| {
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
@@ -156,7 +156,7 @@ fn passing_low_turnout_voting_should_work() {
 
 		let r = Democracy::inject_referendum(
 			2,
-			set_balance_proposal_hash_and_note(2),
+			set_balance_proposal(2),
 			VoteThreshold::SuperMajorityApprove,
 			0,
 		);
diff --git a/substrate/frame/democracy/src/types.rs b/substrate/frame/democracy/src/types.rs
index 52ab8a40eb3e33647151b055ed6d2eff317f5124..4b7f1a0fac45c2d435bd7fd4702304446c2f582f 100644
--- a/substrate/frame/democracy/src/types.rs
+++ b/substrate/frame/democracy/src/types.rs
@@ -18,7 +18,7 @@
 //! Miscellaneous additional datatypes.
 
 use crate::{AccountVote, Conviction, Vote, VoteThreshold};
-use codec::{Decode, Encode};
+use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
 use sp_runtime::{
 	traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Saturating, Zero},
@@ -26,7 +26,7 @@ use sp_runtime::{
 };
 
 /// Info regarding an ongoing referendum.
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
 pub struct Tally<Balance> {
 	/// The number of aye votes, expressed in terms of post-conviction lock-vote.
 	pub ayes: Balance,
@@ -37,7 +37,9 @@ pub struct Tally<Balance> {
 }
 
 /// Amount of votes and capital placed in delegation for an account.
-#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+#[derive(
+	Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo,
+)]
 pub struct Delegations<Balance> {
 	/// The number of votes (this is post-conviction).
 	pub votes: Balance,
@@ -160,12 +162,12 @@ impl<
 }
 
 /// Info regarding an ongoing referendum.
-#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub struct ReferendumStatus<BlockNumber, Hash, Balance> {
+#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub struct ReferendumStatus<BlockNumber, Proposal, Balance> {
 	/// When voting on this referendum will end.
 	pub end: BlockNumber,
-	/// The hash of the proposal being voted on.
-	pub proposal_hash: Hash,
+	/// The proposal being voted on.
+	pub proposal: Proposal,
 	/// The thresholding mechanism to determine whether it passed.
 	pub threshold: VoteThreshold,
 	/// The delay (in blocks) to wait after a successful referendum before deploying.
@@ -175,23 +177,23 @@ pub struct ReferendumStatus<BlockNumber, Hash, Balance> {
 }
 
 /// Info regarding a referendum, present or past.
-#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub enum ReferendumInfo<BlockNumber, Hash, Balance> {
+#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+pub enum ReferendumInfo<BlockNumber, Proposal, Balance> {
 	/// Referendum is happening, the arg is the block number at which it will end.
-	Ongoing(ReferendumStatus<BlockNumber, Hash, Balance>),
+	Ongoing(ReferendumStatus<BlockNumber, Proposal, Balance>),
 	/// Referendum finished at `end`, and has been `approved` or rejected.
 	Finished { approved: bool, end: BlockNumber },
 }
 
-impl<BlockNumber, Hash, Balance: Default> ReferendumInfo<BlockNumber, Hash, Balance> {
+impl<BlockNumber, Proposal, Balance: Default> ReferendumInfo<BlockNumber, Proposal, Balance> {
 	/// Create a new instance.
 	pub fn new(
 		end: BlockNumber,
-		proposal_hash: Hash,
+		proposal: Proposal,
 		threshold: VoteThreshold,
 		delay: BlockNumber,
 	) -> Self {
-		let s = ReferendumStatus { end, proposal_hash, threshold, delay, tally: Tally::default() };
+		let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() };
 		ReferendumInfo::Ongoing(s)
 	}
 }
diff --git a/substrate/frame/democracy/src/vote.rs b/substrate/frame/democracy/src/vote.rs
index c74623d4dfeb8923a8a9e79e3c8e94befcda3ada..122f54febd8cf1df1db1d6cae1517ed3e8144a90 100644
--- a/substrate/frame/democracy/src/vote.rs
+++ b/substrate/frame/democracy/src/vote.rs
@@ -18,11 +18,12 @@
 //! The vote datatype.
 
 use crate::{Conviction, Delegations, ReferendumIndex};
-use codec::{Decode, Encode, EncodeLike, Input, Output};
+use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output};
+use frame_support::traits::Get;
 use scale_info::TypeInfo;
 use sp_runtime::{
 	traits::{Saturating, Zero},
-	RuntimeDebug,
+	BoundedVec, RuntimeDebug,
 };
 use sp_std::prelude::*;
 
@@ -39,6 +40,12 @@ impl Encode for Vote {
 	}
 }
 
+impl MaxEncodedLen for Vote {
+	fn max_encoded_len() -> usize {
+		1
+	}
+}
+
 impl EncodeLike for Vote {}
 
 impl Decode for Vote {
@@ -66,7 +73,7 @@ impl TypeInfo for Vote {
 }
 
 /// A vote for a referendum of a particular account.
-#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
+#[derive(Encode, MaxEncodedLen, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
 pub enum AccountVote<Balance> {
 	/// A standard vote, one-way (approve or reject) with a given amount of conviction.
 	Standard { vote: Vote, balance: Balance },
@@ -107,7 +114,18 @@ impl<Balance: Saturating> AccountVote<Balance> {
 
 /// A "prior" lock, i.e. a lock for some now-forgotten reason.
 #[derive(
-	Encode, Decode, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo,
+	Encode,
+	MaxEncodedLen,
+	Decode,
+	Default,
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	RuntimeDebug,
+	TypeInfo,
 )]
 pub struct PriorLock<BlockNumber, Balance>(BlockNumber, Balance);
 
@@ -131,13 +149,15 @@ impl<BlockNumber: Ord + Copy + Zero, Balance: Ord + Copy + Zero> PriorLock<Block
 }
 
 /// An indicator for what an account is doing; it can either be delegating or voting.
-#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
-pub enum Voting<Balance, AccountId, BlockNumber> {
+#[derive(Clone, Encode, Decode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
+#[codec(mel_bound(skip_type_params(MaxVotes)))]
+#[scale_info(skip_type_params(MaxVotes))]
+pub enum Voting<Balance, AccountId, BlockNumber, MaxVotes: Get<u32>> {
 	/// The account is voting directly. `delegations` is the total amount of post-conviction voting
 	/// weight that it controls from those that have delegated to it.
 	Direct {
 		/// The current votes of the account.
-		votes: Vec<(ReferendumIndex, AccountVote<Balance>)>,
+		votes: BoundedVec<(ReferendumIndex, AccountVote<Balance>), MaxVotes>,
 		/// The total amount of delegations that this account has received.
 		delegations: Delegations<Balance>,
 		/// Any pre-existing locks from past voting/delegating activity.
@@ -155,20 +175,24 @@ pub enum Voting<Balance, AccountId, BlockNumber> {
 	},
 }
 
-impl<Balance: Default, AccountId, BlockNumber: Zero> Default
-	for Voting<Balance, AccountId, BlockNumber>
+impl<Balance: Default, AccountId, BlockNumber: Zero, MaxVotes: Get<u32>> Default
+	for Voting<Balance, AccountId, BlockNumber, MaxVotes>
 {
 	fn default() -> Self {
 		Voting::Direct {
-			votes: Vec::new(),
+			votes: Default::default(),
 			delegations: Default::default(),
 			prior: PriorLock(Zero::zero(), Default::default()),
 		}
 	}
 }
 
-impl<Balance: Saturating + Ord + Zero + Copy, BlockNumber: Ord + Copy + Zero, AccountId>
-	Voting<Balance, AccountId, BlockNumber>
+impl<
+		Balance: Saturating + Ord + Zero + Copy,
+		BlockNumber: Ord + Copy + Zero,
+		AccountId,
+		MaxVotes: Get<u32>,
+	> Voting<Balance, AccountId, BlockNumber, MaxVotes>
 {
 	pub fn rejig(&mut self, now: BlockNumber) {
 		match self {
diff --git a/substrate/frame/democracy/src/vote_threshold.rs b/substrate/frame/democracy/src/vote_threshold.rs
index 443d6b116619803afdfe911d32e7453113496fd2..e8ef91def9820fd558171da75439ea7ddf14db06 100644
--- a/substrate/frame/democracy/src/vote_threshold.rs
+++ b/substrate/frame/democracy/src/vote_threshold.rs
@@ -18,7 +18,7 @@
 //! Voting thresholds.
 
 use crate::Tally;
-use codec::{Decode, Encode};
+use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
 #[cfg(feature = "std")]
 use serde::{Deserialize, Serialize};
@@ -26,7 +26,9 @@ use sp_runtime::traits::{IntegerSquareRoot, Zero};
 use sp_std::ops::{Add, Div, Mul, Rem};
 
 /// A means of determining if a vote is past pass threshold.
-#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, TypeInfo)]
+#[derive(
+	Clone, Copy, PartialEq, Eq, Encode, MaxEncodedLen, Decode, sp_runtime::RuntimeDebug, TypeInfo,
+)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub enum VoteThreshold {
 	/// A supermajority of approvals is needed to pass this vote.
diff --git a/substrate/frame/democracy/src/weights.rs b/substrate/frame/democracy/src/weights.rs
index 272921ed3a15d3f17cfac4091f536afc25432e98..0a3b717938022aabfcb5d037ded244f63f4d8868 100644
--- a/substrate/frame/democracy/src/weights.rs
+++ b/substrate/frame/democracy/src/weights.rs
@@ -18,22 +18,24 @@
 //! Autogenerated weights for pallet_democracy
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/substrate
+// /home/benchbot/cargo_target_dir/production/substrate
 // benchmark
 // pallet
-// --chain=dev
 // --steps=50
 // --repeat=20
-// --pallet=pallet_democracy
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
-// --template=./.maintain/frame-weight-template.hbs
+// --heap-pages=4096
+// --pallet=pallet_democracy
+// --chain=dev
 // --output=./frame/democracy/src/weights.rs
+// --template=./.maintain/frame-weight-template.hbs
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -45,27 +47,23 @@ use sp_std::marker::PhantomData;
 /// Weight functions needed for pallet_democracy.
 pub trait WeightInfo {
 	fn propose() -> Weight;
-	fn second(s: u32, ) -> Weight;
-	fn vote_new(r: u32, ) -> Weight;
-	fn vote_existing(r: u32, ) -> Weight;
+	fn second() -> Weight;
+	fn vote_new() -> Weight;
+	fn vote_existing() -> Weight;
 	fn emergency_cancel() -> Weight;
-	fn blacklist(p: u32, ) -> Weight;
-	fn external_propose(v: u32, ) -> Weight;
+	fn blacklist() -> Weight;
+	fn external_propose() -> Weight;
 	fn external_propose_majority() -> Weight;
 	fn external_propose_default() -> Weight;
 	fn fast_track() -> Weight;
-	fn veto_external(v: u32, ) -> Weight;
-	fn cancel_proposal(p: u32, ) -> Weight;
+	fn veto_external() -> Weight;
+	fn cancel_proposal() -> Weight;
 	fn cancel_referendum() -> Weight;
-	fn cancel_queued(r: u32, ) -> Weight;
 	fn on_initialize_base(r: u32, ) -> Weight;
 	fn on_initialize_base_with_launch_period(r: u32, ) -> Weight;
 	fn delegate(r: u32, ) -> Weight;
 	fn undelegate(r: u32, ) -> Weight;
 	fn clear_public_proposals() -> Weight;
-	fn note_preimage(b: u32, ) -> Weight;
-	fn note_imminent_preimage(b: u32, ) -> Weight;
-	fn reap_preimage(b: u32, ) -> Weight;
 	fn unlock_remove(r: u32, ) -> Weight;
 	fn unlock_set(r: u32, ) -> Weight;
 	fn remove_vote(r: u32, ) -> Weight;
@@ -80,125 +78,103 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	// Storage: Democracy Blacklist (r:1 w:0)
 	// Storage: Democracy DepositOf (r:0 w:1)
 	fn propose() -> Weight {
-		Weight::from_ref_time(48_328_000 as u64)
+		Weight::from_ref_time(57_410_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy DepositOf (r:1 w:1)
-	fn second(s: u32, ) -> Weight {
-		Weight::from_ref_time(30_923_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64))
+	fn second() -> Weight {
+		Weight::from_ref_time(49_224_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
-	fn vote_new(r: u32, ) -> Weight {
-		Weight::from_ref_time(40_345_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64))
+	fn vote_new() -> Weight {
+		Weight::from_ref_time(60_933_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
-	fn vote_existing(r: u32, ) -> Weight {
-		Weight::from_ref_time(39_853_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64))
+	fn vote_existing() -> Weight {
+		Weight::from_ref_time(60_393_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy Cancellations (r:1 w:1)
 	fn emergency_cancel() -> Weight {
-		Weight::from_ref_time(19_364_000 as u64)
+		Weight::from_ref_time(24_588_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy PublicProps (r:1 w:1)
+	// Storage: Democracy DepositOf (r:1 w:1)
+	// Storage: System Account (r:1 w:1)
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy Blacklist (r:0 w:1)
-	// Storage: Democracy DepositOf (r:1 w:1)
-	// Storage: System Account (r:1 w:1)
-	fn blacklist(p: u32, ) -> Weight {
-		Weight::from_ref_time(57_708_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64))
+	fn blacklist() -> Weight {
+		Weight::from_ref_time(91_226_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(6 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy Blacklist (r:1 w:0)
-	fn external_propose(v: u32, ) -> Weight {
-		Weight::from_ref_time(10_714_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64))
+	fn external_propose() -> Weight {
+		Weight::from_ref_time(18_898_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:0 w:1)
 	fn external_propose_majority() -> Weight {
-		Weight::from_ref_time(3_697_000 as u64)
+		Weight::from_ref_time(5_136_000 as u64)
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:0 w:1)
 	fn external_propose_default() -> Weight {
-		Weight::from_ref_time(3_831_000 as u64)
+		Weight::from_ref_time(5_243_000 as u64)
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy ReferendumCount (r:1 w:1)
 	// Storage: Democracy ReferendumInfoOf (r:0 w:1)
 	fn fast_track() -> Weight {
-		Weight::from_ref_time(20_271_000 as u64)
+		Weight::from_ref_time(24_275_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy Blacklist (r:1 w:1)
-	fn veto_external(v: u32, ) -> Weight {
-		Weight::from_ref_time(21_319_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64))
+	fn veto_external() -> Weight {
+		Weight::from_ref_time(30_988_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy PublicProps (r:1 w:1)
 	// Storage: Democracy DepositOf (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
-	fn cancel_proposal(p: u32, ) -> Weight {
-		Weight::from_ref_time(43_960_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64))
+	fn cancel_proposal() -> Weight {
+		Weight::from_ref_time(78_515_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:0 w:1)
 	fn cancel_referendum() -> Weight {
-		Weight::from_ref_time(13_475_000 as u64)
+		Weight::from_ref_time(16_155_000 as u64)
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
-	// Storage: Scheduler Lookup (r:1 w:1)
-	// Storage: Scheduler Agenda (r:1 w:1)
-	fn cancel_queued(r: u32, ) -> Weight {
-		Weight::from_ref_time(24_320_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
-	}
 	// Storage: Democracy LowestUnbaked (r:1 w:1)
 	// Storage: Democracy ReferendumCount (r:1 w:0)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:0)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:0)
+	/// The range of component `r` is `[0, 99]`.
 	fn on_initialize_base(r: u32, ) -> Weight {
-		Weight::from_ref_time(3_428_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(7_007_000 as u64)
+			// Standard Error: 2_686
+			.saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
@@ -208,33 +184,36 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	// Storage: Democracy LastTabledWasExternal (r:1 w:0)
 	// Storage: Democracy NextExternal (r:1 w:0)
 	// Storage: Democracy PublicProps (r:1 w:0)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:0)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:0)
+	/// The range of component `r` is `[0, 99]`.
 	fn on_initialize_base_with_launch_period(r: u32, ) -> Weight {
-		Weight::from_ref_time(7_867_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(9_528_000 as u64)
+			// Standard Error: 2_521
+			.saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy VotingOf (r:3 w:3)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:2)
+	/// The range of component `r` is `[0, 99]`.
 	fn delegate(r: u32, ) -> Weight {
-		Weight::from_ref_time(37_902_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(46_787_000 as u64)
+			// Standard Error: 2_943
+			.saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(T::DbWeight::get().writes(4 as u64))
 			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64)))
 	}
 	// Storage: Democracy VotingOf (r:2 w:2)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:2)
+	/// The range of component `r` is `[0, 99]`.
 	fn undelegate(r: u32, ) -> Weight {
-		Weight::from_ref_time(21_272_000 as u64)
-			// Standard Error: 3_000
-			.saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(29_789_000 as u64)
+			// Standard Error: 2_324
+			.saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
@@ -242,69 +221,48 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	}
 	// Storage: Democracy PublicProps (r:0 w:1)
 	fn clear_public_proposals() -> Weight {
-		Weight::from_ref_time(4_913_000 as u64)
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	fn note_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(27_986_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	fn note_imminent_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(20_058_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	// Storage: System Account (r:1 w:0)
-	fn reap_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(28_619_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
+		Weight::from_ref_time(6_519_000 as u64)
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
+	/// The range of component `r` is `[0, 99]`.
 	fn unlock_remove(r: u32, ) -> Weight {
-		Weight::from_ref_time(26_619_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(28_884_000 as u64)
+			// Standard Error: 2_631
+			.saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
+	/// The range of component `r` is `[0, 99]`.
 	fn unlock_set(r: u32, ) -> Weight {
-		Weight::from_ref_time(25_373_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(33_498_000 as u64)
+			// Standard Error: 622
+			.saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
+	/// The range of component `r` is `[1, 100]`.
 	fn remove_vote(r: u32, ) -> Weight {
-		Weight::from_ref_time(15_961_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(18_201_000 as u64)
+			// Standard Error: 1_007
+			.saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
+	/// The range of component `r` is `[1, 100]`.
 	fn remove_other_vote(r: u32, ) -> Weight {
-		Weight::from_ref_time(15_992_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(18_455_000 as u64)
+			// Standard Error: 951
+			.saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
@@ -317,125 +275,103 @@ impl WeightInfo for () {
 	// Storage: Democracy Blacklist (r:1 w:0)
 	// Storage: Democracy DepositOf (r:0 w:1)
 	fn propose() -> Weight {
-		Weight::from_ref_time(48_328_000 as u64)
+		Weight::from_ref_time(57_410_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy DepositOf (r:1 w:1)
-	fn second(s: u32, ) -> Weight {
-		Weight::from_ref_time(30_923_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64))
+	fn second() -> Weight {
+		Weight::from_ref_time(49_224_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
-	fn vote_new(r: u32, ) -> Weight {
-		Weight::from_ref_time(40_345_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64))
+	fn vote_new() -> Weight {
+		Weight::from_ref_time(60_933_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
-	fn vote_existing(r: u32, ) -> Weight {
-		Weight::from_ref_time(39_853_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64))
+	fn vote_existing() -> Weight {
+		Weight::from_ref_time(60_393_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy Cancellations (r:1 w:1)
 	fn emergency_cancel() -> Weight {
-		Weight::from_ref_time(19_364_000 as u64)
+		Weight::from_ref_time(24_588_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy PublicProps (r:1 w:1)
+	// Storage: Democracy DepositOf (r:1 w:1)
+	// Storage: System Account (r:1 w:1)
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy Blacklist (r:0 w:1)
-	// Storage: Democracy DepositOf (r:1 w:1)
-	// Storage: System Account (r:1 w:1)
-	fn blacklist(p: u32, ) -> Weight {
-		Weight::from_ref_time(57_708_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64))
+	fn blacklist() -> Weight {
+		Weight::from_ref_time(91_226_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(5 as u64))
 			.saturating_add(RocksDbWeight::get().writes(6 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy Blacklist (r:1 w:0)
-	fn external_propose(v: u32, ) -> Weight {
-		Weight::from_ref_time(10_714_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64))
+	fn external_propose() -> Weight {
+		Weight::from_ref_time(18_898_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:0 w:1)
 	fn external_propose_majority() -> Weight {
-		Weight::from_ref_time(3_697_000 as u64)
+		Weight::from_ref_time(5_136_000 as u64)
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:0 w:1)
 	fn external_propose_default() -> Weight {
-		Weight::from_ref_time(3_831_000 as u64)
+		Weight::from_ref_time(5_243_000 as u64)
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy ReferendumCount (r:1 w:1)
 	// Storage: Democracy ReferendumInfoOf (r:0 w:1)
 	fn fast_track() -> Weight {
-		Weight::from_ref_time(20_271_000 as u64)
+		Weight::from_ref_time(24_275_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy NextExternal (r:1 w:1)
 	// Storage: Democracy Blacklist (r:1 w:1)
-	fn veto_external(v: u32, ) -> Weight {
-		Weight::from_ref_time(21_319_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64))
+	fn veto_external() -> Weight {
+		Weight::from_ref_time(30_988_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy PublicProps (r:1 w:1)
 	// Storage: Democracy DepositOf (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
-	fn cancel_proposal(p: u32, ) -> Weight {
-		Weight::from_ref_time(43_960_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64))
+	fn cancel_proposal() -> Weight {
+		Weight::from_ref_time(78_515_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:0 w:1)
 	fn cancel_referendum() -> Weight {
-		Weight::from_ref_time(13_475_000 as u64)
+		Weight::from_ref_time(16_155_000 as u64)
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
-	// Storage: Scheduler Lookup (r:1 w:1)
-	// Storage: Scheduler Agenda (r:1 w:1)
-	fn cancel_queued(r: u32, ) -> Weight {
-		Weight::from_ref_time(24_320_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
-			.saturating_add(RocksDbWeight::get().writes(2 as u64))
-	}
 	// Storage: Democracy LowestUnbaked (r:1 w:1)
 	// Storage: Democracy ReferendumCount (r:1 w:0)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:0)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:0)
+	/// The range of component `r` is `[0, 99]`.
 	fn on_initialize_base(r: u32, ) -> Weight {
-		Weight::from_ref_time(3_428_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(7_007_000 as u64)
+			// Standard Error: 2_686
+			.saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
@@ -445,33 +381,36 @@ impl WeightInfo for () {
 	// Storage: Democracy LastTabledWasExternal (r:1 w:0)
 	// Storage: Democracy NextExternal (r:1 w:0)
 	// Storage: Democracy PublicProps (r:1 w:0)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:0)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:0)
+	/// The range of component `r` is `[0, 99]`.
 	fn on_initialize_base_with_launch_period(r: u32, ) -> Weight {
-		Weight::from_ref_time(7_867_000 as u64)
-			// Standard Error: 2_000
-			.saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(9_528_000 as u64)
+			// Standard Error: 2_521
+			.saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(5 as u64))
 			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy VotingOf (r:3 w:3)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:2)
+	/// The range of component `r` is `[0, 99]`.
 	fn delegate(r: u32, ) -> Weight {
-		Weight::from_ref_time(37_902_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(46_787_000 as u64)
+			// Standard Error: 2_943
+			.saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(RocksDbWeight::get().writes(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64)))
 	}
 	// Storage: Democracy VotingOf (r:2 w:2)
-	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
+	// Storage: Democracy ReferendumInfoOf (r:2 w:2)
+	/// The range of component `r` is `[0, 99]`.
 	fn undelegate(r: u32, ) -> Weight {
-		Weight::from_ref_time(21_272_000 as u64)
-			// Standard Error: 3_000
-			.saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(29_789_000 as u64)
+			// Standard Error: 2_324
+			.saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64)))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
@@ -479,69 +418,48 @@ impl WeightInfo for () {
 	}
 	// Storage: Democracy PublicProps (r:0 w:1)
 	fn clear_public_proposals() -> Weight {
-		Weight::from_ref_time(4_913_000 as u64)
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	fn note_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(27_986_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	fn note_imminent_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(20_058_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: Democracy Preimages (r:1 w:1)
-	// Storage: System Account (r:1 w:0)
-	fn reap_preimage(b: u32, ) -> Weight {
-		Weight::from_ref_time(28_619_000 as u64)
-			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
+		Weight::from_ref_time(6_519_000 as u64)
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
+	/// The range of component `r` is `[0, 99]`.
 	fn unlock_remove(r: u32, ) -> Weight {
-		Weight::from_ref_time(26_619_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(28_884_000 as u64)
+			// Standard Error: 2_631
+			.saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy VotingOf (r:1 w:1)
 	// Storage: Balances Locks (r:1 w:1)
 	// Storage: System Account (r:1 w:1)
+	/// The range of component `r` is `[0, 99]`.
 	fn unlock_set(r: u32, ) -> Weight {
-		Weight::from_ref_time(25_373_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(33_498_000 as u64)
+			// Standard Error: 622
+			.saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
+	/// The range of component `r` is `[1, 100]`.
 	fn remove_vote(r: u32, ) -> Weight {
-		Weight::from_ref_time(15_961_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(18_201_000 as u64)
+			// Standard Error: 1_007
+			.saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Democracy ReferendumInfoOf (r:1 w:1)
 	// Storage: Democracy VotingOf (r:1 w:1)
+	/// The range of component `r` is `[1, 100]`.
 	fn remove_other_vote(r: u32, ) -> Weight {
-		Weight::from_ref_time(15_992_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64))
+		Weight::from_ref_time(18_455_000 as u64)
+			// Standard Error: 951
+			.saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs
index 747d1e9f271066ece26883c8e414ad2eb82d51d8..20628da50937a73da759b4fd64df8542b62aa1d9 100644
--- a/substrate/frame/identity/src/tests.rs
+++ b/substrate/frame/identity/src/tests.rs
@@ -268,7 +268,7 @@ fn registration_should_work() {
 		let mut three_fields = ten();
 		three_fields.additional.try_push(Default::default()).unwrap();
 		three_fields.additional.try_push(Default::default()).unwrap();
-		assert_eq!(three_fields.additional.try_push(Default::default()), Err(()));
+		assert!(three_fields.additional.try_push(Default::default()).is_err());
 		assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten())));
 		assert_eq!(Identity::identity(10).unwrap().info, ten());
 		assert_eq!(Balances::free_balance(10), 90);
diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml
index 6c8b5fbaa7362f7b3dc97fa592f0c7c5152bfcf5..bfd0870d30c22c5a67e0486060871c0581dc169e 100644
--- a/substrate/frame/multisig/Cargo.toml
+++ b/substrate/frame/multisig/Cargo.toml
@@ -22,6 +22,9 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/
 sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
 sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
 
+# third party
+log = { version = "0.4.17", default-features = false }
+
 [dev-dependencies]
 pallet-balances = { version = "4.0.0-dev", path = "../balances" }
 sp-core = { version = "6.0.0", path = "../../primitives/core" }
diff --git a/substrate/frame/multisig/src/benchmarking.rs b/substrate/frame/multisig/src/benchmarking.rs
index c0b0097b0723609faedb7e1f8e966ac94916bec4..d949414e31cb37a7be2a0060f4cbe359f620bc1c 100644
--- a/substrate/frame/multisig/src/benchmarking.rs
+++ b/substrate/frame/multisig/src/benchmarking.rs
@@ -31,7 +31,7 @@ const SEED: u32 = 0;
 fn setup_multi<T: Config>(
 	s: u32,
 	z: u32,
-) -> Result<(Vec<T::AccountId>, OpaqueCall<T>), &'static str> {
+) -> Result<(Vec<T::AccountId>, Box<<T as Config>::RuntimeCall>), &'static str> {
 	let mut signatories: Vec<T::AccountId> = Vec::new();
 	for i in 0..s {
 		let signatory = account("signatory", i, SEED);
@@ -44,8 +44,7 @@ fn setup_multi<T: Config>(
 	// Must first convert to runtime call type.
 	let call: <T as Config>::RuntimeCall =
 		frame_system::Call::<T>::remark { remark: vec![0; z as usize] }.into();
-	let call_data = OpaqueCall::<T>::from_encoded(call.encode());
-	Ok((signatories, call_data))
+	Ok((signatories, Box::new(call)))
 }
 
 benchmarks! {
@@ -74,35 +73,15 @@ benchmarks! {
 		// Transaction Length
 		let z in 0 .. 10_000;
 		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let call_hash = blake2_256(call.encoded());
-		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
-		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		// Whitelist caller account from further DB operations.
-		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
-		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, Weight::zero())
-	verify {
-		assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
-		assert!(!Calls::<T>::contains_key(call_hash));
-	}
-
-	as_multi_create_store {
-		// Signatories, need at least 2 total people
-		let s in 2 .. T::MaxSignatories::get() as u32;
-		// Transaction Length
-		let z in 0 .. 10_000;
-		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
 		// Whitelist caller account from further DB operations.
 		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
 		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, Weight::zero())
+	}: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero())
 	verify {
 		assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
-		assert!(Calls::<T>::contains_key(call_hash));
 	}
 
 	as_multi_approve {
@@ -111,49 +90,22 @@ benchmarks! {
 		// Transaction Length
 		let z in 0 .. 10_000;
 		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let call_hash = blake2_256(call.encoded());
-		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
-		let mut signatories2 = signatories.clone();
-		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		// before the call, get the timepoint
-		let timepoint = Multisig::<T>::timepoint();
-		// Create the multi, storing for worst case
-		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
-		assert!(Calls::<T>::contains_key(call_hash));
-		let caller2 = signatories2.remove(0);
-		// Whitelist caller account from further DB operations.
-		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
-		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::zero())
-	verify {
-		let multisig = Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
-		assert_eq!(multisig.approvals.len(), 2);
-	}
-
-	as_multi_approve_store {
-		// Signatories, need at least 3 people (so we don't complete the multisig)
-		let s in 3 .. T::MaxSignatories::get() as u32;
-		// Transaction Length
-		let z in 0 .. 10_000;
-		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let mut signatories2 = signatories.clone();
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
 		// before the call, get the timepoint
 		let timepoint = Multisig::<T>::timepoint();
-		// Create the multi, not storing
-		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, Weight::zero())?;
-		assert!(!Calls::<T>::contains_key(call_hash));
+		// Create the multi
+		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?;
 		let caller2 = signatories2.remove(0);
 		// Whitelist caller account from further DB operations.
 		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
 		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, Weight::zero())
+	}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero())
 	verify {
 		let multisig = Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
 		assert_eq!(multisig.approvals.len(), 2);
-		assert!(Calls::<T>::contains_key(call_hash));
 	}
 
 	as_multi_complete {
@@ -162,27 +114,27 @@ benchmarks! {
 		// Transaction Length
 		let z in 0 .. 10_000;
 		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let mut signatories2 = signatories.clone();
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
 		// before the call, get the timepoint
 		let timepoint = Multisig::<T>::timepoint();
-		// Create the multi, storing it for worst case
-		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
+		// Create the multi
+		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?;
 		// Everyone except the first person approves
 		for i in 1 .. s - 1 {
 			let mut signatories_loop = signatories2.clone();
 			let caller_loop = signatories_loop.remove(i as usize);
 			let o = RawOrigin::Signed(caller_loop).into();
-			Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?;
+			Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?;
 		}
 		let caller2 = signatories2.remove(0);
 		assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
 		// Whitelist caller account from further DB operations.
 		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
 		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::MAX)
+	}: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX)
 	verify {
 		assert!(!Multisigs::<T>::contains_key(&multi_account_id, call_hash));
 	}
@@ -195,7 +147,7 @@ benchmarks! {
 		let (mut signatories, call) = setup_multi::<T>(s, z)?;
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		// Whitelist caller account from further DB operations.
 		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
 		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
@@ -214,7 +166,7 @@ benchmarks! {
 		let mut signatories2 = signatories.clone();
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		// before the call, get the timepoint
 		let timepoint = Multisig::<T>::timepoint();
 		// Create the multi
@@ -224,7 +176,6 @@ benchmarks! {
 			signatories,
 			None,
 			call,
-			false,
 			Weight::zero()
 		)?;
 		let caller2 = signatories2.remove(0);
@@ -237,45 +188,6 @@ benchmarks! {
 		assert_eq!(multisig.approvals.len(), 2);
 	}
 
-	approve_as_multi_complete {
-		// Signatories, need at least 2 people
-		let s in 2 .. T::MaxSignatories::get() as u32;
-		// Transaction Length, not a component
-		let z = 10_000;
-		let (mut signatories, call) = setup_multi::<T>(s, z)?;
-		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
-		let mut signatories2 = signatories.clone();
-		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
-		let call_hash = blake2_256(call.encoded());
-		// before the call, get the timepoint
-		let timepoint = Multisig::<T>::timepoint();
-		// Create the multi
-		Multisig::<T>::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?;
-		// Everyone except the first person approves
-		for i in 1 .. s - 1 {
-			let mut signatories_loop = signatories2.clone();
-			let caller_loop = signatories_loop.remove(i as usize);
-			let o = RawOrigin::Signed(caller_loop).into();
-			Multisig::<T>::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?;
-		}
-		let caller2 = signatories2.remove(0);
-		assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
-		// Whitelist caller account from further DB operations.
-		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
-		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
-	}: approve_as_multi(
-		RawOrigin::Signed(caller2),
-		s as u16,
-		signatories2,
-		Some(timepoint),
-		call_hash,
-		Weight::MAX
-	)
-	verify {
-		assert!(!Multisigs::<T>::contains_key(multi_account_id, call_hash));
-	}
-
 	cancel_as_multi {
 		// Signatories, need at least 2 people
 		let s in 2 .. T::MaxSignatories::get() as u32;
@@ -284,20 +196,18 @@ benchmarks! {
 		let (mut signatories, call) = setup_multi::<T>(s, z)?;
 		let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
 		let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
-		let call_hash = blake2_256(call.encoded());
+		let call_hash = call.using_encoded(blake2_256);
 		let timepoint = Multisig::<T>::timepoint();
 		// Create the multi
 		let o = RawOrigin::Signed(caller.clone()).into();
-		Multisig::<T>::as_multi(o, s as u16, signatories.clone(), None, call, true, Weight::zero())?;
+		Multisig::<T>::as_multi(o, s as u16, signatories.clone(), None, call, Weight::zero())?;
 		assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
-		assert!(Calls::<T>::contains_key(call_hash));
 		// Whitelist caller account from further DB operations.
 		let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
 		frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
 	}: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash)
 	verify {
 		assert!(!Multisigs::<T>::contains_key(multi_account_id, call_hash));
-		assert!(!Calls::<T>::contains_key(call_hash));
 	}
 
 	impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test);
diff --git a/substrate/frame/multisig/src/lib.rs b/substrate/frame/multisig/src/lib.rs
index 3bdb47ffc4568c88d17a615e4dd0d626dede8dbf..e3031cc830209d4c19be1f6f4da313cd82e00478 100644
--- a/substrate/frame/multisig/src/lib.rs
+++ b/substrate/frame/multisig/src/lib.rs
@@ -47,6 +47,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 mod benchmarking;
+pub mod migrations;
 mod tests;
 pub mod weights;
 
@@ -57,7 +58,7 @@ use frame_support::{
 		PostDispatchInfo,
 	},
 	ensure,
-	traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque},
+	traits::{Currency, Get, ReservableCurrency},
 	weights::Weight,
 	RuntimeDebug,
 };
@@ -73,6 +74,20 @@ pub use weights::WeightInfo;
 
 pub use pallet::*;
 
+/// The log target of this pallet.
+pub const LOG_TARGET: &'static str = "runtime::multisig";
+
+// syntactic sugar for logging.
+#[macro_export]
+macro_rules! log {
+	($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
+		log::$level!(
+			target: crate::LOG_TARGET,
+			concat!("[{:?}] ✍️ ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
+		)
+	};
+}
+
 type BalanceOf<T> =
 	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
 
@@ -100,12 +115,10 @@ pub struct Multisig<BlockNumber, Balance, AccountId> {
 	approvals: Vec<AccountId>,
 }
 
-type OpaqueCall<T> = WrapperKeepOpaque<<T as Config>::RuntimeCall>;
-
 type CallHash = [u8; 32];
 
 enum CallOrHash<T: Config> {
-	Call(OpaqueCall<T>, bool),
+	Call(<T as Config>::RuntimeCall),
 	Hash([u8; 32]),
 }
 
@@ -152,9 +165,13 @@ pub mod pallet {
 		type WeightInfo: WeightInfo;
 	}
 
+	/// The current storage version.
+	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
 	#[pallet::without_storage_info]
+	#[pallet::storage_version(STORAGE_VERSION)]
 	pub struct Pallet<T>(_);
 
 	/// The set of open multisig operations.
@@ -168,10 +185,6 @@ pub mod pallet {
 		Multisig<T::BlockNumber, BalanceOf<T>, T::AccountId>,
 	>;
 
-	#[pallet::storage]
-	pub type Calls<T: Config> =
-		StorageMap<_, Identity, [u8; 32], (OpaqueCall<T>, T::AccountId, BalanceOf<T>)>;
-
 	#[pallet::error]
 	pub enum Error<T> {
 		/// Threshold must be 2 or greater.
@@ -343,13 +356,13 @@ pub mod pallet {
 		///   taken for its lifetime of `DepositBase + threshold * DepositFactor`.
 		/// -------------------------------
 		/// - DB Weight:
-		///     - Reads: Multisig Storage, [Caller Account], Calls (if `store_call`)
-		///     - Writes: Multisig Storage, [Caller Account], Calls (if `store_call`)
+		///     - Reads: Multisig Storage, [Caller Account]
+		///     - Writes: Multisig Storage, [Caller Account]
 		/// - Plus Call Weight
 		/// # </weight>
 		#[pallet::weight({
 			let s = other_signatories.len() as u32;
-			let z = call.encoded_len() as u32;
+			let z = call.using_encoded(|d| d.len()) as u32;
 
 			T::WeightInfo::as_multi_create(s, z)
 			.max(T::WeightInfo::as_multi_create_store(s, z))
@@ -362,8 +375,7 @@ pub mod pallet {
 			threshold: u16,
 			other_signatories: Vec<T::AccountId>,
 			maybe_timepoint: Option<Timepoint<T::BlockNumber>>,
-			call: OpaqueCall<T>,
-			store_call: bool,
+			call: Box<<T as Config>::RuntimeCall>,
 			max_weight: Weight,
 		) -> DispatchResultWithPostInfo {
 			let who = ensure_signed(origin)?;
@@ -372,7 +384,7 @@ pub mod pallet {
 				threshold,
 				other_signatories,
 				maybe_timepoint,
-				CallOrHash::Call(call, store_call),
+				CallOrHash::Call(*call),
 				max_weight,
 			)
 		}
@@ -462,8 +474,8 @@ pub mod pallet {
 		/// - Storage: removes one item.
 		/// ----------------------------------
 		/// - DB Weight:
-		///     - Read: Multisig Storage, [Caller Account], Refund Account, Calls
-		///     - Write: Multisig Storage, [Caller Account], Refund Account, Calls
+		///     - Read: Multisig Storage, [Caller Account], Refund Account
+		///     - Write: Multisig Storage, [Caller Account], Refund Account
 		/// # </weight>
 		#[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))]
 		pub fn cancel_as_multi(
@@ -489,7 +501,6 @@ pub mod pallet {
 			let err_amount = T::Currency::unreserve(&m.depositor, m.deposit);
 			debug_assert!(err_amount.is_zero());
 			<Multisigs<T>>::remove(&id, &call_hash);
-			Self::clear_call(&call_hash);
 
 			Self::deposit_event(Event::MultisigCancelled {
 				cancelling: who,
@@ -531,13 +542,12 @@ impl<T: Config> Pallet<T> {
 		let id = Self::multi_account_id(&signatories, threshold);
 
 		// Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`.
-		let (call_hash, call_len, maybe_call, store) = match call_or_hash {
-			CallOrHash::Call(call, should_store) => {
-				let call_hash = blake2_256(call.encoded());
-				let call_len = call.encoded_len();
-				(call_hash, call_len, Some(call), should_store)
+		let (call_hash, call_len, maybe_call) = match call_or_hash {
+			CallOrHash::Call(call) => {
+				let (call_hash, call_len) = call.using_encoded(|d| (blake2_256(d), d.len()));
+				(call_hash, call_len, Some(call))
 			},
-			CallOrHash::Hash(h) => (h, 0, None, false),
+			CallOrHash::Hash(h) => (h, 0, None),
 		};
 
 		// Branch on whether the operation has already started or not.
@@ -556,13 +566,7 @@ impl<T: Config> Pallet<T> {
 			}
 
 			// We only bother fetching/decoding call if we know that we're ready to execute.
-			let maybe_approved_call = if approvals >= threshold {
-				Self::get_call(&call_hash, maybe_call.as_ref())
-			} else {
-				None
-			};
-
-			if let Some((call, call_len)) = maybe_approved_call {
+			if let Some(call) = maybe_call.filter(|_| approvals >= threshold) {
 				// verify weight
 				ensure!(
 					call.get_dispatch_info().weight.all_lte(max_weight),
@@ -572,7 +576,6 @@ impl<T: Config> Pallet<T> {
 				// Clean up storage before executing call to avoid an possibility of reentrancy
 				// attack.
 				<Multisigs<T>>::remove(&id, call_hash);
-				Self::clear_call(&call_hash);
 				T::Currency::unreserve(&m.depositor, m.deposit);
 
 				let result = call.dispatch(RawOrigin::Signed(id.clone()).into());
@@ -596,19 +599,6 @@ impl<T: Config> Pallet<T> {
 				// We cannot dispatch the call now; either it isn't available, or it is, but we
 				// don't have threshold approvals even with our signature.
 
-				// Store the call if desired.
-				let stored = if let Some(data) = maybe_call.filter(|_| store) {
-					Self::store_call_and_reserve(
-						who.clone(),
-						&call_hash,
-						data,
-						BalanceOf::<T>::zero(),
-					)?;
-					true
-				} else {
-					false
-				};
-
 				if let Some(pos) = maybe_pos {
 					// Record approval.
 					m.approvals.insert(pos, who.clone());
@@ -622,17 +612,11 @@ impl<T: Config> Pallet<T> {
 				} else {
 					// If we already approved and didn't store the Call, then this was useless and
 					// we report an error.
-					ensure!(stored, Error::<T>::AlreadyApproved);
+					Err(Error::<T>::AlreadyApproved)?
 				}
 
-				let final_weight = if stored {
-					T::WeightInfo::as_multi_approve_store(
-						other_signatories_len as u32,
-						call_len as u32,
-					)
-				} else {
-					T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32)
-				};
+				let final_weight =
+					T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32);
 				// Call is not made, so the actual weight does not include call
 				Ok(Some(final_weight).into())
 			}
@@ -643,14 +627,7 @@ impl<T: Config> Pallet<T> {
 			// Just start the operation by recording it in storage.
 			let deposit = T::DepositBase::get() + T::DepositFactor::get() * threshold.into();
 
-			// Store the call if desired.
-			let stored = if let Some(data) = maybe_call.filter(|_| store) {
-				Self::store_call_and_reserve(who.clone(), &call_hash, data, deposit)?;
-				true
-			} else {
-				T::Currency::reserve(&who, deposit)?;
-				false
-			};
+			T::Currency::reserve(&who, deposit)?;
 
 			<Multisigs<T>>::insert(
 				&id,
@@ -664,58 +641,13 @@ impl<T: Config> Pallet<T> {
 			);
 			Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash });
 
-			let final_weight = if stored {
-				T::WeightInfo::as_multi_create_store(other_signatories_len as u32, call_len as u32)
-			} else {
-				T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32)
-			};
+			let final_weight =
+				T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32);
 			// Call is not made, so the actual weight does not include call
 			Ok(Some(final_weight).into())
 		}
 	}
 
-	/// Place a call's encoded data in storage, reserving funds as appropriate.
-	///
-	/// We store `data` here because storing `call` would result in needing another `.encode`.
-	///
-	/// Returns a `bool` indicating whether the data did end up being stored.
-	fn store_call_and_reserve(
-		who: T::AccountId,
-		hash: &[u8; 32],
-		data: OpaqueCall<T>,
-		other_deposit: BalanceOf<T>,
-	) -> DispatchResult {
-		ensure!(!Calls::<T>::contains_key(hash), Error::<T>::AlreadyStored);
-		let deposit = other_deposit +
-			T::DepositBase::get() +
-			T::DepositFactor::get() *
-				BalanceOf::<T>::from(((data.encoded_len() + 31) / 32) as u32);
-		T::Currency::reserve(&who, deposit)?;
-		Calls::<T>::insert(&hash, (data, who, deposit));
-		Ok(())
-	}
-
-	/// Attempt to decode and return the call, provided by the user or from storage.
-	fn get_call(
-		hash: &[u8; 32],
-		maybe_known: Option<&OpaqueCall<T>>,
-	) -> Option<(<T as Config>::RuntimeCall, usize)> {
-		maybe_known.map_or_else(
-			|| {
-				Calls::<T>::get(hash)
-					.and_then(|(data, ..)| Some((data.try_decode()?, data.encoded_len())))
-			},
-			|data| Some((data.try_decode()?, data.encoded_len())),
-		)
-	}
-
-	/// Attempt to remove a call from storage, returning any deposit on it to the owner.
-	fn clear_call(hash: &[u8; 32]) {
-		if let Some((_, who, deposit)) = Calls::<T>::take(hash) {
-			T::Currency::unreserve(&who, deposit);
-		}
-	}
-
 	/// The current `Timepoint`.
 	pub fn timepoint() -> Timepoint<T::BlockNumber> {
 		Timepoint {
diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5085297cde433f38e1016c24b5a4896e498afbcf
--- /dev/null
+++ b/substrate/frame/multisig/src/migrations.rs
@@ -0,0 +1,86 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Migrations for Multisig Pallet
+
+use super::*;
+use frame_support::{
+	dispatch::GetStorageVersion,
+	traits::{OnRuntimeUpgrade, WrapperKeepOpaque},
+	Identity,
+};
+
+#[cfg(feature = "try-runtime")]
+use frame_support::ensure;
+
+pub mod v1 {
+	use super::*;
+
+	type OpaqueCall<T> = WrapperKeepOpaque<<T as Config>::RuntimeCall>;
+
+	#[frame_support::storage_alias]
+	type Calls<T: Config> = StorageMap<
+		Pallet<T>,
+		Identity,
+		[u8; 32],
+		(OpaqueCall<T>, <T as frame_system::Config>::AccountId, BalanceOf<T>),
+	>;
+
+	pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
+	impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
+		#[cfg(feature = "try-runtime")]
+		fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
+			let onchain = Pallet::<T>::on_chain_storage_version();
+
+			ensure!(onchain < 1, "this migration can be deleted");
+
+			log!(info, "Number of calls to refund and delete: {}", Calls::<T>::iter().count());
+
+			Ok(Vec::new())
+		}
+
+		fn on_runtime_upgrade() -> Weight {
+			let current = Pallet::<T>::current_storage_version();
+			let onchain = Pallet::<T>::on_chain_storage_version();
+
+			if onchain > 0 {
+				log!(info, "MigrateToV1 should be removed");
+				return T::DbWeight::get().reads(1)
+			}
+
+			Calls::<T>::drain().for_each(|(_call_hash, (_data, caller, deposit))| {
+				T::Currency::unreserve(&caller, deposit);
+			});
+
+			current.put::<Pallet<T>>();
+
+			<T as frame_system::Config>::BlockWeights::get().max_block
+		}
+
+		#[cfg(feature = "try-runtime")]
+		fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
+			let onchain = Pallet::<T>::on_chain_storage_version();
+			ensure!(onchain < 2, "this migration needs to be removed");
+			ensure!(onchain == 1, "this migration needs to be run");
+			ensure!(
+				Calls::<T>::iter().count() == 0,
+				"there are some dangling calls that need to be destroyed and refunded"
+			);
+			Ok(())
+		}
+	}
+}
diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs
index b24a06f454368edbae2f4f67b0627c937e54b719..f753b6f386c562f18567f37d767bd2605d7bc998 100644
--- a/substrate/frame/multisig/src/tests.rs
+++ b/substrate/frame/multisig/src/tests.rs
@@ -34,7 +34,6 @@ use sp_runtime::{
 
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
 type Block = frame_system::mocking::MockBlock<Test>;
-type OpaqueCall = super::OpaqueCall<Test>;
 
 frame_support::construct_runtime!(
 	pub enum Test where
@@ -130,8 +129,8 @@ fn now() -> Timepoint<u64> {
 	Multisig::timepoint()
 }
 
-fn call_transfer(dest: u64, value: u64) -> RuntimeCall {
-	RuntimeCall::Balances(BalancesCall::transfer { dest, value })
+fn call_transfer(dest: u64, value: u64) -> Box<RuntimeCall> {
+	Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest, value }))
 }
 
 #[test]
@@ -144,14 +143,12 @@ fn multisig_deposit_is_taken_and_returned() {
 
 		let call = call_transfer(6, 15);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
 		assert_ok!(Multisig::as_multi(
 			RuntimeOrigin::signed(1),
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			Weight::zero()
 		));
 		assert_eq!(Balances::free_balance(1), 2);
@@ -162,8 +159,7 @@ fn multisig_deposit_is_taken_and_returned() {
 			2,
 			vec![1, 3],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call,
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(1), 5);
@@ -171,96 +167,6 @@ fn multisig_deposit_is_taken_and_returned() {
 	});
 }
 
-#[test]
-fn multisig_deposit_is_taken_and_returned_with_call_storage() {
-	new_test_ext().execute_with(|| {
-		let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2);
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
-
-		let call = call_transfer(6, 15);
-		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
-		assert_ok!(Multisig::as_multi(
-			RuntimeOrigin::signed(1),
-			2,
-			vec![2, 3],
-			None,
-			OpaqueCall::from_encoded(data),
-			true,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(1), 0);
-		assert_eq!(Balances::reserved_balance(1), 5);
-
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(2),
-			2,
-			vec![1, 3],
-			Some(now()),
-			hash,
-			call_weight
-		));
-		assert_eq!(Balances::free_balance(1), 5);
-		assert_eq!(Balances::reserved_balance(1), 0);
-	});
-}
-
-#[test]
-fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() {
-	new_test_ext().execute_with(|| {
-		let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3);
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
-
-		let call = call_transfer(6, 15);
-		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
-
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(1),
-			3,
-			vec![2, 3],
-			None,
-			hash,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(1), 1);
-		assert_eq!(Balances::reserved_balance(1), 4);
-
-		assert_ok!(Multisig::as_multi(
-			RuntimeOrigin::signed(2),
-			3,
-			vec![1, 3],
-			Some(now()),
-			OpaqueCall::from_encoded(data),
-			true,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(2), 3);
-		assert_eq!(Balances::reserved_balance(2), 2);
-		assert_eq!(Balances::free_balance(1), 1);
-		assert_eq!(Balances::reserved_balance(1), 4);
-
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(3),
-			3,
-			vec![1, 2],
-			Some(now()),
-			hash,
-			call_weight
-		));
-		assert_eq!(Balances::free_balance(1), 5);
-		assert_eq!(Balances::reserved_balance(1), 0);
-		assert_eq!(Balances::free_balance(2), 5);
-		assert_eq!(Balances::reserved_balance(2), 0);
-	});
-}
-
 #[test]
 fn cancel_multisig_returns_deposit() {
 	new_test_ext().execute_with(|| {
@@ -298,8 +204,8 @@ fn timepoint_checking_works() {
 		assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
 		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
 
-		let call = call_transfer(6, 15).encode();
-		let hash = blake2_256(&call);
+		let call = call_transfer(6, 15);
+		let hash = blake2_256(&call.encode());
 
 		assert_noop!(
 			Multisig::approve_as_multi(
@@ -328,8 +234,7 @@ fn timepoint_checking_works() {
 				2,
 				vec![1, 3],
 				None,
-				OpaqueCall::from_encoded(call.clone()),
-				false,
+				call.clone(),
 				Weight::zero()
 			),
 			Error::<Test>::NoTimepoint,
@@ -341,8 +246,7 @@ fn timepoint_checking_works() {
 				2,
 				vec![1, 3],
 				Some(later),
-				OpaqueCall::from_encoded(call),
-				false,
+				call,
 				Weight::zero()
 			),
 			Error::<Test>::WrongTimepoint,
@@ -350,41 +254,6 @@ fn timepoint_checking_works() {
 	});
 }
 
-#[test]
-fn multisig_2_of_3_works_with_call_storing() {
-	new_test_ext().execute_with(|| {
-		let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2);
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
-		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
-
-		let call = call_transfer(6, 15);
-		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
-		assert_ok!(Multisig::as_multi(
-			RuntimeOrigin::signed(1),
-			2,
-			vec![2, 3],
-			None,
-			OpaqueCall::from_encoded(data),
-			true,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(6), 0);
-
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(2),
-			2,
-			vec![1, 3],
-			Some(now()),
-			hash,
-			call_weight
-		));
-		assert_eq!(Balances::free_balance(6), 15);
-	});
-}
-
 #[test]
 fn multisig_2_of_3_works() {
 	new_test_ext().execute_with(|| {
@@ -395,8 +264,7 @@ fn multisig_2_of_3_works() {
 
 		let call = call_transfer(6, 15);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
+		let hash = blake2_256(&call.encode());
 		assert_ok!(Multisig::approve_as_multi(
 			RuntimeOrigin::signed(1),
 			2,
@@ -412,8 +280,7 @@ fn multisig_2_of_3_works() {
 			2,
 			vec![1, 3],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call,
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(6), 15);
@@ -430,8 +297,7 @@ fn multisig_3_of_3_works() {
 
 		let call = call_transfer(6, 15);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
+		let hash = blake2_256(&call.encode());
 		assert_ok!(Multisig::approve_as_multi(
 			RuntimeOrigin::signed(1),
 			3,
@@ -455,8 +321,7 @@ fn multisig_3_of_3_works() {
 			3,
 			vec![1, 2],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call,
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(6), 15);
@@ -492,68 +357,6 @@ fn cancel_multisig_works() {
 	});
 }
 
-#[test]
-fn cancel_multisig_with_call_storage_works() {
-	new_test_ext().execute_with(|| {
-		let call = call_transfer(6, 15).encode();
-		let hash = blake2_256(&call);
-		assert_ok!(Multisig::as_multi(
-			RuntimeOrigin::signed(1),
-			3,
-			vec![2, 3],
-			None,
-			OpaqueCall::from_encoded(call),
-			true,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(1), 4);
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(2),
-			3,
-			vec![1, 3],
-			Some(now()),
-			hash,
-			Weight::zero()
-		));
-		assert_noop!(
-			Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash),
-			Error::<Test>::NotOwner,
-		);
-		assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),);
-		assert_eq!(Balances::free_balance(1), 10);
-	});
-}
-
-#[test]
-fn cancel_multisig_with_alt_call_storage_works() {
-	new_test_ext().execute_with(|| {
-		let call = call_transfer(6, 15).encode();
-		let hash = blake2_256(&call);
-		assert_ok!(Multisig::approve_as_multi(
-			RuntimeOrigin::signed(1),
-			3,
-			vec![2, 3],
-			None,
-			hash,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(1), 6);
-		assert_ok!(Multisig::as_multi(
-			RuntimeOrigin::signed(2),
-			3,
-			vec![1, 3],
-			Some(now()),
-			OpaqueCall::from_encoded(call),
-			true,
-			Weight::zero()
-		));
-		assert_eq!(Balances::free_balance(2), 8);
-		assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash));
-		assert_eq!(Balances::free_balance(1), 10);
-		assert_eq!(Balances::free_balance(2), 10);
-	});
-}
-
 #[test]
 fn multisig_2_of_3_as_multi_works() {
 	new_test_ext().execute_with(|| {
@@ -564,14 +367,12 @@ fn multisig_2_of_3_as_multi_works() {
 
 		let call = call_transfer(6, 15);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
 		assert_ok!(Multisig::as_multi(
 			RuntimeOrigin::signed(1),
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			Weight::zero()
 		));
 		assert_eq!(Balances::free_balance(6), 0);
@@ -581,8 +382,7 @@ fn multisig_2_of_3_as_multi_works() {
 			2,
 			vec![1, 3],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call,
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(6), 15);
@@ -599,18 +399,15 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
 
 		let call1 = call_transfer(6, 10);
 		let call1_weight = call1.get_dispatch_info().weight;
-		let data1 = call1.encode();
 		let call2 = call_transfer(7, 5);
 		let call2_weight = call2.get_dispatch_info().weight;
-		let data2 = call2.encode();
 
 		assert_ok!(Multisig::as_multi(
 			RuntimeOrigin::signed(1),
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data1.clone()),
-			false,
+			call1.clone(),
 			Weight::zero()
 		));
 		assert_ok!(Multisig::as_multi(
@@ -618,8 +415,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
 			2,
 			vec![1, 3],
 			None,
-			OpaqueCall::from_encoded(data2.clone()),
-			false,
+			call2.clone(),
 			Weight::zero()
 		));
 		assert_ok!(Multisig::as_multi(
@@ -627,8 +423,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
 			2,
 			vec![1, 2],
 			Some(now()),
-			OpaqueCall::from_encoded(data1),
-			false,
+			call1,
 			call1_weight
 		));
 		assert_ok!(Multisig::as_multi(
@@ -636,8 +431,7 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() {
 			2,
 			vec![1, 2],
 			Some(now()),
-			OpaqueCall::from_encoded(data2),
-			false,
+			call2,
 			call2_weight
 		));
 
@@ -656,15 +450,13 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
 
 		let call = call_transfer(6, 10);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
+		let hash = blake2_256(&call.encode());
 		assert_ok!(Multisig::as_multi(
 			RuntimeOrigin::signed(1),
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			Weight::zero()
 		));
 		assert_ok!(Multisig::as_multi(
@@ -672,8 +464,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
 			2,
 			vec![1, 3],
 			Some(now()),
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(multi), 5);
@@ -683,8 +474,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			Weight::zero()
 		));
 		assert_ok!(Multisig::as_multi(
@@ -692,8 +482,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
 			2,
 			vec![1, 2],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call.clone(),
 			call_weight
 		));
 
@@ -714,15 +503,14 @@ fn multisig_2_of_3_cannot_reissue_same_call() {
 #[test]
 fn minimum_threshold_check_works() {
 	new_test_ext().execute_with(|| {
-		let call = call_transfer(6, 15).encode();
+		let call = call_transfer(6, 15);
 		assert_noop!(
 			Multisig::as_multi(
 				RuntimeOrigin::signed(1),
 				0,
 				vec![2],
 				None,
-				OpaqueCall::from_encoded(call.clone()),
-				false,
+				call.clone(),
 				Weight::zero()
 			),
 			Error::<Test>::MinimumThreshold,
@@ -733,8 +521,7 @@ fn minimum_threshold_check_works() {
 				1,
 				vec![2],
 				None,
-				OpaqueCall::from_encoded(call.clone()),
-				false,
+				call.clone(),
 				Weight::zero()
 			),
 			Error::<Test>::MinimumThreshold,
@@ -745,15 +532,14 @@ fn minimum_threshold_check_works() {
 #[test]
 fn too_many_signatories_fails() {
 	new_test_ext().execute_with(|| {
-		let call = call_transfer(6, 15).encode();
+		let call = call_transfer(6, 15);
 		assert_noop!(
 			Multisig::as_multi(
 				RuntimeOrigin::signed(1),
 				2,
 				vec![2, 3, 4],
 				None,
-				OpaqueCall::from_encoded(call),
-				false,
+				call.clone(),
 				Weight::zero()
 			),
 			Error::<Test>::TooManySignatories,
@@ -815,8 +601,8 @@ fn multisig_1_of_3_works() {
 		assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5));
 		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
 
-		let call = call_transfer(6, 15).encode();
-		let hash = blake2_256(&call);
+		let call = call_transfer(6, 15);
+		let hash = blake2_256(&call.encode());
 		assert_noop!(
 			Multisig::approve_as_multi(
 				RuntimeOrigin::signed(1),
@@ -834,17 +620,15 @@ fn multisig_1_of_3_works() {
 				1,
 				vec![2, 3],
 				None,
-				OpaqueCall::from_encoded(call),
-				false,
+				call.clone(),
 				Weight::zero()
 			),
 			Error::<Test>::MinimumThreshold,
 		);
-		let boxed_call = Box::new(call_transfer(6, 15));
 		assert_ok!(Multisig::as_multi_threshold_1(
 			RuntimeOrigin::signed(1),
 			vec![2, 3],
-			boxed_call
+			call_transfer(6, 15)
 		));
 
 		assert_eq!(Balances::free_balance(6), 15);
@@ -871,14 +655,12 @@ fn weight_check_works() {
 		assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5));
 
 		let call = call_transfer(6, 15);
-		let data = call.encode();
 		assert_ok!(Multisig::as_multi(
 			RuntimeOrigin::signed(1),
 			2,
 			vec![2, 3],
 			None,
-			OpaqueCall::from_encoded(data.clone()),
-			false,
+			call.clone(),
 			Weight::zero()
 		));
 		assert_eq!(Balances::free_balance(6), 0);
@@ -889,8 +671,7 @@ fn weight_check_works() {
 				2,
 				vec![1, 3],
 				Some(now()),
-				OpaqueCall::from_encoded(data),
-				false,
+				call,
 				Weight::zero()
 			),
 			Error::<Test>::MaxWeightTooLow,
@@ -911,8 +692,7 @@ fn multisig_handles_no_preimage_after_all_approve() {
 
 		let call = call_transfer(6, 15);
 		let call_weight = call.get_dispatch_info().weight;
-		let data = call.encode();
-		let hash = blake2_256(&data);
+		let hash = blake2_256(&call.encode());
 		assert_ok!(Multisig::approve_as_multi(
 			RuntimeOrigin::signed(1),
 			3,
@@ -944,8 +724,7 @@ fn multisig_handles_no_preimage_after_all_approve() {
 			3,
 			vec![1, 2],
 			Some(now()),
-			OpaqueCall::from_encoded(data),
-			false,
+			call,
 			call_weight
 		));
 		assert_eq!(Balances::free_balance(6), 15);
diff --git a/substrate/frame/nicks/src/lib.rs b/substrate/frame/nicks/src/lib.rs
index 953cf39cd12db581333cae703e8d396264c7d089..b3238630d31745e03ad24108dc6723403af6aa08 100644
--- a/substrate/frame/nicks/src/lib.rs
+++ b/substrate/frame/nicks/src/lib.rs
@@ -140,7 +140,7 @@ pub mod pallet {
 			let sender = ensure_signed(origin)?;
 
 			let bounded_name: BoundedVec<_, _> =
-				name.try_into().map_err(|()| Error::<T>::TooLong)?;
+				name.try_into().map_err(|_| Error::<T>::TooLong)?;
 			ensure!(bounded_name.len() >= T::MinLength::get() as usize, Error::<T>::TooShort);
 
 			let deposit = if let Some((_, deposit)) = <NameOf<T>>::get(&sender) {
@@ -229,7 +229,7 @@ pub mod pallet {
 			T::ForceOrigin::ensure_origin(origin)?;
 
 			let bounded_name: BoundedVec<_, _> =
-				name.try_into().map_err(|()| Error::<T>::TooLong)?;
+				name.try_into().map_err(|_| Error::<T>::TooLong)?;
 			let target = T::Lookup::lookup(target)?;
 			let deposit = <NameOf<T>>::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero);
 			<NameOf<T>>::insert(&target, (bounded_name, deposit));
diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml
index 9a5cc186cca64f13c9d3254f4c97cf202ad20f07..77046f4fb58b6bee69ad682043d8b7a6a15e62f2 100644
--- a/substrate/frame/preimage/Cargo.toml
+++ b/substrate/frame/preimage/Cargo.toml
@@ -19,6 +19,7 @@ sp-core = { version = "6.0.0", default-features = false, optional = true, path =
 sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
 sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
 sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
+log = { version = "0.4.17", default-features = false }
 
 [dev-dependencies]
 pallet-balances = { version = "4.0.0-dev", path = "../balances" }
@@ -36,10 +37,13 @@ std = [
 	"frame-benchmarking?/std",
 	"frame-support/std",
 	"frame-system/std",
+	"log/std",
 	"scale-info/std",
 	"sp-core/std",
 	"sp-io/std",
 	"sp-runtime/std",
 	"sp-std/std",
 ]
-try-runtime = ["frame-support/try-runtime"]
+try-runtime = [
+	"frame-support/try-runtime",
+]
diff --git a/substrate/frame/preimage/src/benchmarking.rs b/substrate/frame/preimage/src/benchmarking.rs
index 3c7be9db573f45c2f25f2945f56bff32a08eaaa4..8a61d7d780bfd788068c4a8e1d0cd016930005be 100644
--- a/substrate/frame/preimage/src/benchmarking.rs
+++ b/substrate/frame/preimage/src/benchmarking.rs
@@ -35,7 +35,7 @@ fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
 }
 
 fn preimage_and_hash<T: Config>() -> (Vec<u8>, T::Hash) {
-	sized_preimage_and_hash::<T>(T::MaxSize::get())
+	sized_preimage_and_hash::<T>(MAX_SIZE)
 }
 
 fn sized_preimage_and_hash<T: Config>(size: u32) -> (Vec<u8>, T::Hash) {
@@ -48,7 +48,7 @@ fn sized_preimage_and_hash<T: Config>(size: u32) -> (Vec<u8>, T::Hash) {
 benchmarks! {
 	// Expensive note - will reserve.
 	note_preimage {
-		let s in 0 .. T::MaxSize::get();
+		let s in 0 .. MAX_SIZE;
 		let caller = funded_account::<T>("caller", 0);
 		whitelist_account!(caller);
 		let (preimage, hash) = sized_preimage_and_hash::<T>(s);
@@ -58,7 +58,7 @@ benchmarks! {
 	}
 	// Cheap note - will not reserve since it was requested.
 	note_requested_preimage {
-		let s in 0 .. T::MaxSize::get();
+		let s in 0 .. MAX_SIZE;
 		let caller = funded_account::<T>("caller", 0);
 		whitelist_account!(caller);
 		let (preimage, hash) = sized_preimage_and_hash::<T>(s);
@@ -69,7 +69,7 @@ benchmarks! {
 	}
 	// Cheap note - will not reserve since it's the manager.
 	note_no_deposit_preimage {
-		let s in 0 .. T::MaxSize::get();
+		let s in 0 .. MAX_SIZE;
 		let (preimage, hash) = sized_preimage_and_hash::<T>(s);
 		assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
 	}: note_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), preimage)
@@ -101,10 +101,12 @@ benchmarks! {
 		let (preimage, hash) = preimage_and_hash::<T>();
 		let noter = funded_account::<T>("noter", 0);
 		whitelist_account!(noter);
-		assert_ok!(Preimage::<T>::note_preimage(RawOrigin::Signed(noter).into(), preimage));
+		assert_ok!(Preimage::<T>::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage));
 	}: _<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
 	verify {
-		assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
+		let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into();
+		let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) };
+		assert_eq!(StatusFor::<T>::get(&hash), Some(s));
 	}
 	// Cheap request - would unreserve the deposit but none was held.
 	request_no_deposit_preimage {
@@ -112,14 +114,16 @@ benchmarks! {
 		assert_ok!(Preimage::<T>::note_preimage(T::ManagerOrigin::successful_origin(), preimage));
 	}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
 	verify {
-		assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
+		let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) };
+		assert_eq!(StatusFor::<T>::get(&hash), Some(s));
 	}
 	// Cheap request - the preimage is not yet noted, so deposit to unreserve.
 	request_unnoted_preimage {
 		let (_, hash) = preimage_and_hash::<T>();
 	}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
 	verify {
-		assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
+		let s = RequestStatus::Requested { deposit: None, count: 1, len: None };
+		assert_eq!(StatusFor::<T>::get(&hash), Some(s));
 	}
 	// Cheap request - the preimage is already requested, so just a counter bump.
 	request_requested_preimage {
@@ -127,7 +131,8 @@ benchmarks! {
 		assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
 	}: request_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
 	verify {
-		assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(2)));
+		let s = RequestStatus::Requested { deposit: None, count: 2, len: None };
+		assert_eq!(StatusFor::<T>::get(&hash), Some(s));
 	}
 
 	// Expensive unrequest - last reference and it's noted, so will destroy the preimage.
@@ -154,7 +159,8 @@ benchmarks! {
 		assert_ok!(Preimage::<T>::request_preimage(T::ManagerOrigin::successful_origin(), hash));
 	}: unrequest_preimage<T::RuntimeOrigin>(T::ManagerOrigin::successful_origin(), hash)
 	verify {
-		assert_eq!(StatusFor::<T>::get(&hash), Some(RequestStatus::Requested(1)));
+		let s = RequestStatus::Requested { deposit: None, count: 1, len: None };
+		assert_eq!(StatusFor::<T>::get(&hash), Some(s));
 	}
 
 	impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test);
diff --git a/substrate/frame/preimage/src/lib.rs b/substrate/frame/preimage/src/lib.rs
index 90f5ac175f54027d16b83af256959c93434ea06a..e899d3643dbbffb89d7ab9e5bd1b6d140c5c3690 100644
--- a/substrate/frame/preimage/src/lib.rs
+++ b/substrate/frame/preimage/src/lib.rs
@@ -30,6 +30,7 @@
 
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
+pub mod migration;
 #[cfg(test)]
 mod mock;
 #[cfg(test)]
@@ -37,15 +38,18 @@ mod tests;
 pub mod weights;
 
 use sp_runtime::traits::{BadOrigin, Hash, Saturating};
-use sp_std::prelude::*;
+use sp_std::{borrow::Cow, prelude::*};
 
 use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::{
 	dispatch::Pays,
 	ensure,
 	pallet_prelude::Get,
-	traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency},
-	BoundedVec,
+	traits::{
+		Currency, Defensive, FetchResult, Hash as PreimageHash, PreimageProvider,
+		PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage,
+	},
+	BoundedSlice, BoundedVec,
 };
 use scale_info::TypeInfo;
 pub use weights::WeightInfo;
@@ -59,20 +63,27 @@ pub use pallet::*;
 #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)]
 pub enum RequestStatus<AccountId, Balance> {
 	/// The associated preimage has not yet been requested by the system. The given deposit (if
-	/// some) is being held until either it becomes requested or the user retracts the primage.
-	Unrequested(Option<(AccountId, Balance)>),
+	/// some) is being held until either it becomes requested or the user retracts the preimage.
+	Unrequested { deposit: (AccountId, Balance), len: u32 },
 	/// There are a non-zero number of outstanding requests for this hash by this chain. If there
-	/// is a preimage registered, then it may be removed iff this counter becomes zero.
-	Requested(u32),
+	/// is a preimage registered, then `len` is `Some` and it may be removed iff this counter
+	/// becomes zero.
+	Requested { deposit: Option<(AccountId, Balance)>, count: u32, len: Option<u32> },
 }
 
 type BalanceOf<T> =
 	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
 
+/// Maximum size of preimage we can store is 4mb.
+const MAX_SIZE: u32 = 4 * 1024 * 1024;
+
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
 
+	/// The current storage version.
+	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
 	#[pallet::config]
 	pub trait Config: frame_system::Config {
 		/// The overarching event type.
@@ -88,9 +99,6 @@ pub mod pallet {
 		/// manage existing preimages.
 		type ManagerOrigin: EnsureOrigin<Self::RuntimeOrigin>;
 
-		/// Max size allowed for a preimage.
-		type MaxSize: Get<u32>;
-
 		/// The base deposit for placing a preimage on chain.
 		type BaseDeposit: Get<BalanceOf<Self>>;
 
@@ -100,6 +108,7 @@ pub mod pallet {
 
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
+	#[pallet::storage_version(STORAGE_VERSION)]
 	pub struct Pallet<T>(PhantomData<T>);
 
 	#[pallet::event]
@@ -116,7 +125,7 @@ pub mod pallet {
 	#[pallet::error]
 	pub enum Error<T> {
 		/// Preimage is too large to store on-chain.
-		TooLarge,
+		TooBig,
 		/// Preimage has already been noted on-chain.
 		AlreadyNoted,
 		/// The user is not authorized to perform this action.
@@ -134,10 +143,9 @@ pub mod pallet {
 	pub(super) type StatusFor<T: Config> =
 		StorageMap<_, Identity, T::Hash, RequestStatus<T::AccountId, BalanceOf<T>>>;
 
-	/// The preimages stored by this pallet.
 	#[pallet::storage]
 	pub(super) type PreimageFor<T: Config> =
-		StorageMap<_, Identity, T::Hash, BoundedVec<u8, T::MaxSize>>;
+		StorageMap<_, Identity, (T::Hash, u32), BoundedVec<u8, ConstU32<MAX_SIZE>>>;
 
 	#[pallet::call]
 	impl<T: Config> Pallet<T> {
@@ -150,9 +158,7 @@ pub mod pallet {
 			// We accept a signed origin which will pay a deposit, or a root origin where a deposit
 			// is not taken.
 			let maybe_sender = Self::ensure_signed_or_manager(origin)?;
-			let bounded_vec =
-				BoundedVec::<u8, T::MaxSize>::try_from(bytes).map_err(|()| Error::<T>::TooLarge)?;
-			let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?;
+			let (system_requested, _) = Self::note_bytes(bytes.into(), maybe_sender.as_ref())?;
 			if system_requested || maybe_sender.is_none() {
 				Ok(Pays::No.into())
 			} else {
@@ -161,6 +167,11 @@ pub mod pallet {
 		}
 
 		/// Clear an unrequested preimage from the runtime storage.
+		///
+		/// If `len` is provided, then it will be a much cheaper operation.
+		///
+		/// - `hash`: The hash of the preimage to be removed from the store.
+		/// - `len`: The length of the preimage of `hash`.
 		#[pallet::weight(T::WeightInfo::unnote_preimage())]
 		pub fn unnote_preimage(origin: OriginFor<T>, hash: T::Hash) -> DispatchResult {
 			let maybe_sender = Self::ensure_signed_or_manager(origin)?;
@@ -203,41 +214,46 @@ impl<T: Config> Pallet<T> {
 
 	/// Store some preimage on chain.
 	///
+	/// If `maybe_depositor` is `None` then it is also requested. If `Some`, then it is not.
+	///
 	/// We verify that the preimage is within the bounds of what the pallet supports.
 	///
 	/// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees.
 	fn note_bytes(
-		preimage: BoundedVec<u8, T::MaxSize>,
+		preimage: Cow<[u8]>,
 		maybe_depositor: Option<&T::AccountId>,
-	) -> Result<bool, DispatchError> {
+	) -> Result<(bool, T::Hash), DispatchError> {
 		let hash = T::Hashing::hash(&preimage);
-		ensure!(!PreimageFor::<T>::contains_key(hash), Error::<T>::AlreadyNoted);
+		let len = preimage.len() as u32;
+		ensure!(len <= MAX_SIZE, Error::<T>::TooBig);
 
-		// We take a deposit only if there is a provided depositor, and the preimage was not
+		// We take a deposit only if there is a provided depositor and the preimage was not
 		// previously requested. This also allows the tx to pay no fee.
-		let was_requested = match (StatusFor::<T>::get(hash), maybe_depositor) {
-			(Some(RequestStatus::Requested(..)), _) => true,
-			(Some(RequestStatus::Unrequested(..)), _) =>
+		let status = match (StatusFor::<T>::get(hash), maybe_depositor) {
+			(Some(RequestStatus::Requested { count, deposit, .. }), _) =>
+				RequestStatus::Requested { count, deposit, len: Some(len) },
+			(Some(RequestStatus::Unrequested { .. }), Some(_)) =>
 				return Err(Error::<T>::AlreadyNoted.into()),
-			(None, None) => {
-				StatusFor::<T>::insert(hash, RequestStatus::Unrequested(None));
-				false
-			},
+			(Some(RequestStatus::Unrequested { len, deposit }), None) =>
+				RequestStatus::Requested { deposit: Some(deposit), count: 1, len: Some(len) },
+			(None, None) => RequestStatus::Requested { count: 1, len: Some(len), deposit: None },
 			(None, Some(depositor)) => {
 				let length = preimage.len() as u32;
 				let deposit = T::BaseDeposit::get()
 					.saturating_add(T::ByteDeposit::get().saturating_mul(length.into()));
 				T::Currency::reserve(depositor, deposit)?;
-				let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit)));
-				StatusFor::<T>::insert(hash, status);
-				false
+				RequestStatus::Unrequested { deposit: (depositor.clone(), deposit), len }
 			},
 		};
+		let was_requested = matches!(status, RequestStatus::Requested { .. });
+		StatusFor::<T>::insert(hash, status);
+
+		let _ = Self::insert(&hash, preimage)
+			.defensive_proof("Unable to insert. Logic error in `note_bytes`?");
 
-		PreimageFor::<T>::insert(hash, preimage);
 		Self::deposit_event(Event::Noted { hash });
 
-		Ok(was_requested)
+		Ok((was_requested, hash))
 	}
 
 	// This function will add a hash to the list of requested preimages.
@@ -245,19 +261,15 @@ impl<T: Config> Pallet<T> {
 	// If the preimage already exists before the request is made, the deposit for the preimage is
 	// returned to the user, and removed from their management.
 	fn do_request_preimage(hash: &T::Hash) {
-		let count = StatusFor::<T>::get(hash).map_or(1, |x| match x {
-			RequestStatus::Requested(mut count) => {
-				count.saturating_inc();
-				count
-			},
-			RequestStatus::Unrequested(None) => 1,
-			RequestStatus::Unrequested(Some((owner, deposit))) => {
-				// Return the deposit - the preimage now has outstanding requests.
-				T::Currency::unreserve(&owner, deposit);
-				1
-			},
-		});
-		StatusFor::<T>::insert(hash, RequestStatus::Requested(count));
+		let (count, len, deposit) =
+			StatusFor::<T>::get(hash).map_or((1, None, None), |x| match x {
+				RequestStatus::Requested { mut count, len, deposit } => {
+					count.saturating_inc();
+					(count, len, deposit)
+				},
+				RequestStatus::Unrequested { deposit, len } => (1, Some(len), Some(deposit)),
+			});
+		StatusFor::<T>::insert(hash, RequestStatus::Requested { count, len, deposit });
 		if count == 1 {
 			Self::deposit_event(Event::Requested { hash: *hash });
 		}
@@ -265,6 +277,8 @@ impl<T: Config> Pallet<T> {
 
 	// Clear a preimage from the storage of the chain, returning any deposit that may be reserved.
 	//
+	// If `len` is provided, it will be a much cheaper operation.
+	//
 	// If `maybe_owner` is provided, we verify that it is the correct owner before clearing the
 	// data.
 	fn do_unnote_preimage(
@@ -272,51 +286,101 @@ impl<T: Config> Pallet<T> {
 		maybe_check_owner: Option<T::AccountId>,
 	) -> DispatchResult {
 		match StatusFor::<T>::get(hash).ok_or(Error::<T>::NotNoted)? {
-			RequestStatus::Unrequested(Some((owner, deposit))) => {
+			RequestStatus::Requested { deposit: Some((owner, deposit)), count, len } => {
 				ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::<T>::NotAuthorized);
 				T::Currency::unreserve(&owner, deposit);
+				StatusFor::<T>::insert(
+					hash,
+					RequestStatus::Requested { deposit: None, count, len },
+				);
+				Ok(())
 			},
-			RequestStatus::Unrequested(None) => {
+			RequestStatus::Requested { deposit: None, .. } => {
 				ensure!(maybe_check_owner.is_none(), Error::<T>::NotAuthorized);
+				Self::do_unrequest_preimage(hash)
+			},
+			RequestStatus::Unrequested { deposit: (owner, deposit), len } => {
+				ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::<T>::NotAuthorized);
+				T::Currency::unreserve(&owner, deposit);
+				StatusFor::<T>::remove(hash);
+
+				Self::remove(hash, len);
+				Self::deposit_event(Event::Cleared { hash: *hash });
+				Ok(())
 			},
-			RequestStatus::Requested(_) => return Err(Error::<T>::Requested.into()),
 		}
-		StatusFor::<T>::remove(hash);
-		PreimageFor::<T>::remove(hash);
-		Self::deposit_event(Event::Cleared { hash: *hash });
-		Ok(())
 	}
 
 	/// Clear a preimage request.
 	fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult {
 		match StatusFor::<T>::get(hash).ok_or(Error::<T>::NotRequested)? {
-			RequestStatus::Requested(mut count) if count > 1 => {
+			RequestStatus::Requested { mut count, len, deposit } if count > 1 => {
 				count.saturating_dec();
-				StatusFor::<T>::insert(hash, RequestStatus::Requested(count));
+				StatusFor::<T>::insert(hash, RequestStatus::Requested { count, len, deposit });
 			},
-			RequestStatus::Requested(count) => {
+			RequestStatus::Requested { count, len, deposit } => {
 				debug_assert!(count == 1, "preimage request counter at zero?");
-				PreimageFor::<T>::remove(hash);
-				StatusFor::<T>::remove(hash);
-				Self::deposit_event(Event::Cleared { hash: *hash });
+				match (len, deposit) {
+					// Preimage was never noted.
+					(None, _) => StatusFor::<T>::remove(hash),
+					// Preimage was noted without owner - just remove it.
+					(Some(len), None) => {
+						Self::remove(hash, len);
+						StatusFor::<T>::remove(hash);
+						Self::deposit_event(Event::Cleared { hash: *hash });
+					},
+					// Preimage was noted with owner - move to unrequested so they can get refund.
+					(Some(len), Some(deposit)) => {
+						StatusFor::<T>::insert(hash, RequestStatus::Unrequested { deposit, len });
+					},
+				}
 			},
-			RequestStatus::Unrequested(_) => return Err(Error::<T>::NotRequested.into()),
+			RequestStatus::Unrequested { .. } => return Err(Error::<T>::NotRequested.into()),
 		}
 		Ok(())
 	}
+
+	fn insert(hash: &T::Hash, preimage: Cow<[u8]>) -> Result<(), ()> {
+		BoundedSlice::<u8, ConstU32<MAX_SIZE>>::try_from(preimage.as_ref())
+			.map(|s| PreimageFor::<T>::insert((hash, s.len() as u32), s))
+	}
+
+	fn remove(hash: &T::Hash, len: u32) {
+		PreimageFor::<T>::remove((hash, len))
+	}
+
+	fn have(hash: &T::Hash) -> bool {
+		Self::len(hash).is_some()
+	}
+
+	fn len(hash: &T::Hash) -> Option<u32> {
+		use RequestStatus::*;
+		match StatusFor::<T>::get(hash) {
+			Some(Requested { len: Some(len), .. }) | Some(Unrequested { len, .. }) => Some(len),
+			_ => None,
+		}
+	}
+
+	fn fetch(hash: &T::Hash, len: Option<u32>) -> FetchResult {
+		let len = len.or_else(|| Self::len(hash)).ok_or(DispatchError::Unavailable)?;
+		PreimageFor::<T>::get((hash, len))
+			.map(|p| p.into_inner())
+			.map(Into::into)
+			.ok_or(DispatchError::Unavailable)
+	}
 }
 
 impl<T: Config> PreimageProvider<T::Hash> for Pallet<T> {
 	fn have_preimage(hash: &T::Hash) -> bool {
-		PreimageFor::<T>::contains_key(hash)
+		Self::have(hash)
 	}
 
 	fn preimage_requested(hash: &T::Hash) -> bool {
-		matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested(..)))
+		matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested { .. }))
 	}
 
 	fn get_preimage(hash: &T::Hash) -> Option<Vec<u8>> {
-		PreimageFor::<T>::get(hash).map(|preimage| preimage.to_vec())
+		Self::fetch(hash, None).ok().map(Cow::into_owned)
 	}
 
 	fn request_preimage(hash: &T::Hash) {
@@ -330,15 +394,60 @@ impl<T: Config> PreimageProvider<T::Hash> for Pallet<T> {
 }
 
 impl<T: Config> PreimageRecipient<T::Hash> for Pallet<T> {
-	type MaxSize = T::MaxSize;
+	type MaxSize = ConstU32<MAX_SIZE>; // 2**22
 
 	fn note_preimage(bytes: BoundedVec<u8, Self::MaxSize>) {
 		// We don't really care if this fails, since that's only the case if someone else has
 		// already noted it.
-		let _ = Self::note_bytes(bytes, None);
+		let _ = Self::note_bytes(bytes.into_inner().into(), None);
 	}
 
 	fn unnote_preimage(hash: &T::Hash) {
+		// Should never fail if authorization check is skipped.
+		let res = Self::do_unrequest_preimage(hash);
+		debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?");
+	}
+}
+
+impl<T: Config<Hash = PreimageHash>> QueryPreimage for Pallet<T> {
+	fn len(hash: &T::Hash) -> Option<u32> {
+		Pallet::<T>::len(hash)
+	}
+
+	fn fetch(hash: &T::Hash, len: Option<u32>) -> FetchResult {
+		Pallet::<T>::fetch(hash, len)
+	}
+
+	fn is_requested(hash: &T::Hash) -> bool {
+		matches!(StatusFor::<T>::get(hash), Some(RequestStatus::Requested { .. }))
+	}
+
+	fn request(hash: &T::Hash) {
+		Self::do_request_preimage(hash)
+	}
+
+	fn unrequest(hash: &T::Hash) {
+		let res = Self::do_unrequest_preimage(hash);
+		debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?");
+	}
+}
+
+impl<T: Config<Hash = PreimageHash>> StorePreimage for Pallet<T> {
+	const MAX_LENGTH: usize = MAX_SIZE as usize;
+
+	fn note(bytes: Cow<[u8]>) -> Result<T::Hash, DispatchError> {
+		// We don't really care if this fails, since that's only the case if someone else has
+		// already noted it.
+		let maybe_hash = Self::note_bytes(bytes, None).map(|(_, h)| h);
+		// Map to the correct trait error.
+		if maybe_hash == Err(DispatchError::from(Error::<T>::TooBig)) {
+			Err(DispatchError::Exhausted)
+		} else {
+			maybe_hash
+		}
+	}
+
+	fn unnote(hash: &T::Hash) {
 		// Should never fail if authorization check is skipped.
 		let res = Self::do_unnote_preimage(hash, None);
 		debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?");
diff --git a/substrate/frame/preimage/src/migration.rs b/substrate/frame/preimage/src/migration.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a5d15c23c758a448c12afc7f23a82221775c6db6
--- /dev/null
+++ b/substrate/frame/preimage/src/migration.rs
@@ -0,0 +1,263 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Storage migrations for the preimage pallet.
+
+use super::*;
+use frame_support::{
+	storage_alias,
+	traits::{ConstU32, OnRuntimeUpgrade},
+};
+use sp_std::collections::btree_map::BTreeMap;
+
+/// The log target.
+const TARGET: &'static str = "runtime::preimage::migration::v1";
+
+/// The original data layout of the preimage pallet without a specific version number.
+mod v0 {
+	use super::*;
+
+	#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)]
+	pub enum RequestStatus<AccountId, Balance> {
+		Unrequested(Option<(AccountId, Balance)>),
+		Requested(u32),
+	}
+
+	#[storage_alias]
+	pub type PreimageFor<T: Config> = StorageMap<
+		Pallet<T>,
+		Identity,
+		<T as frame_system::Config>::Hash,
+		BoundedVec<u8, ConstU32<MAX_SIZE>>,
+	>;
+
+	#[storage_alias]
+	pub type StatusFor<T: Config> = StorageMap<
+		Pallet<T>,
+		Identity,
+		<T as frame_system::Config>::Hash,
+		RequestStatus<<T as frame_system::Config>::AccountId, BalanceOf<T>>,
+	>;
+
+	/// Returns the number of images or `None` if the storage is corrupted.
+	#[cfg(feature = "try-runtime")]
+	pub fn image_count<T: Config>() -> Option<u32> {
+		let images = v0::PreimageFor::<T>::iter_values().count() as u32;
+		let status = v0::StatusFor::<T>::iter_values().count() as u32;
+
+		if images == status {
+			Some(images)
+		} else {
+			None
+		}
+	}
+}
+
+pub mod v1 {
+	use super::*;
+
+	/// Migration for moving preimage from V0 to V1 storage.
+	///
+	/// Note: This needs to be run with the same hashing algorithm as before
+	/// since it is not re-hashing the preimages.
+	pub struct Migration<T>(sp_std::marker::PhantomData<T>);
+
+	impl<T: Config> OnRuntimeUpgrade for Migration<T> {
+		#[cfg(feature = "try-runtime")]
+		fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 0, "can only upgrade from version 0");
+
+			let images = v0::image_count::<T>().expect("v0 storage corrupted");
+			log::info!(target: TARGET, "Migrating {} images", &images);
+			Ok((images as u32).encode())
+		}
+
+		fn on_runtime_upgrade() -> Weight {
+			let mut weight = T::DbWeight::get().reads(1);
+			if StorageVersion::get::<Pallet<T>>() != 0 {
+				log::warn!(
+					target: TARGET,
+					"skipping MovePreimagesIntoBuckets: executed on wrong storage version.\
+				Expected version 0"
+				);
+				return weight
+			}
+
+			let status = v0::StatusFor::<T>::drain().collect::<Vec<_>>();
+			weight.saturating_accrue(T::DbWeight::get().reads(status.len() as u64));
+
+			let preimages = v0::PreimageFor::<T>::drain().collect::<BTreeMap<_, _>>();
+			weight.saturating_accrue(T::DbWeight::get().reads(preimages.len() as u64));
+
+			for (hash, status) in status.into_iter() {
+				let preimage = if let Some(preimage) = preimages.get(&hash) {
+					preimage
+				} else {
+					log::error!(target: TARGET, "preimage not found for hash {:?}", &hash);
+					continue
+				};
+				let len = preimage.len() as u32;
+				if len > MAX_SIZE {
+					log::error!(
+						target: TARGET,
+						"preimage too large for hash {:?}, len: {}",
+						&hash,
+						len
+					);
+					continue
+				}
+
+				let status = match status {
+					v0::RequestStatus::Unrequested(deposit) => match deposit {
+						Some(deposit) => RequestStatus::Unrequested { deposit, len },
+						// `None` depositor becomes system-requested.
+						None =>
+							RequestStatus::Requested { deposit: None, count: 1, len: Some(len) },
+					},
+					v0::RequestStatus::Requested(count) if count == 0 => {
+						log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash);
+						continue
+					},
+					v0::RequestStatus::Requested(count) =>
+						RequestStatus::Requested { deposit: None, count, len: Some(len) },
+				};
+				log::trace!(target: TARGET, "Moving preimage {:?} with len {}", hash, len);
+
+				crate::StatusFor::<T>::insert(hash, status);
+				crate::PreimageFor::<T>::insert(&(hash, len), preimage);
+
+				weight.saturating_accrue(T::DbWeight::get().writes(2));
+			}
+			StorageVersion::new(1).put::<Pallet<T>>();
+
+			weight.saturating_add(T::DbWeight::get().writes(1))
+		}
+
+		#[cfg(feature = "try-runtime")]
+		fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
+			let old_images: u32 =
+				Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
+			let new_images = image_count::<T>().expect("V1 storage corrupted");
+
+			if new_images != old_images {
+				log::error!(
+					target: TARGET,
+					"migrated {} images, expected {}",
+					new_images,
+					old_images
+				);
+			}
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 1, "must upgrade");
+			Ok(())
+		}
+	}
+
+	/// Returns the number of images or `None` if the storage is corrupted.
+	#[cfg(feature = "try-runtime")]
+	pub fn image_count<T: Config>() -> Option<u32> {
+		// Use iter_values() to ensure that the values are decodable.
+		let images = crate::PreimageFor::<T>::iter_values().count() as u32;
+		let status = crate::StatusFor::<T>::iter_values().count() as u32;
+
+		if images == status {
+			Some(images)
+		} else {
+			None
+		}
+	}
+}
+
+#[cfg(test)]
+#[cfg(feature = "try-runtime")]
+mod test {
+	use super::*;
+	use crate::mock::{Test as T, *};
+
+	use frame_support::bounded_vec;
+
+	#[test]
+	fn migration_works() {
+		new_test_ext().execute_with(|| {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 0);
+			// Insert some preimages into the v0 storage:
+
+			// Case 1: Unrequested without deposit
+			let (p, h) = preimage::<T>(128);
+			v0::PreimageFor::<T>::insert(h, p);
+			v0::StatusFor::<T>::insert(h, v0::RequestStatus::Unrequested(None));
+			// Case 2: Unrequested with deposit
+			let (p, h) = preimage::<T>(1024);
+			v0::PreimageFor::<T>::insert(h, p);
+			v0::StatusFor::<T>::insert(h, v0::RequestStatus::Unrequested(Some((1, 1))));
+			// Case 3: Requested by 0 (invalid)
+			let (p, h) = preimage::<T>(8192);
+			v0::PreimageFor::<T>::insert(h, p);
+			v0::StatusFor::<T>::insert(h, v0::RequestStatus::Requested(0));
+			// Case 4: Requested by 10
+			let (p, h) = preimage::<T>(65536);
+			v0::PreimageFor::<T>::insert(h, p);
+			v0::StatusFor::<T>::insert(h, v0::RequestStatus::Requested(10));
+
+			assert_eq!(v0::image_count::<T>(), Some(4));
+			assert_eq!(v1::image_count::<T>(), None, "V1 storage should be corrupted");
+
+			let state = v1::Migration::<T>::pre_upgrade().unwrap();
+			let _w = v1::Migration::<T>::on_runtime_upgrade();
+			v1::Migration::<T>::post_upgrade(state).unwrap();
+
+			// V0 and V1 share the same prefix, so `iter_values` still counts the same.
+			assert_eq!(v0::image_count::<T>(), Some(3));
+			assert_eq!(v1::image_count::<T>(), Some(3)); // One gets skipped therefore 3.
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 1);
+
+			// Case 1: Unrequested without deposit becomes system-requested
+			let (p, h) = preimage::<T>(128);
+			assert_eq!(crate::PreimageFor::<T>::get(&(h, 128)), Some(p));
+			assert_eq!(
+				crate::StatusFor::<T>::get(h),
+				Some(RequestStatus::Requested { deposit: None, count: 1, len: Some(128) })
+			);
+			// Case 2: Unrequested with deposit becomes unrequested
+			let (p, h) = preimage::<T>(1024);
+			assert_eq!(crate::PreimageFor::<T>::get(&(h, 1024)), Some(p));
+			assert_eq!(
+				crate::StatusFor::<T>::get(h),
+				Some(RequestStatus::Unrequested { deposit: (1, 1), len: 1024 })
+			);
+			// Case 3: Requested by 0 should be skipped
+			let (_, h) = preimage::<T>(8192);
+			assert_eq!(crate::PreimageFor::<T>::get(&(h, 8192)), None);
+			assert_eq!(crate::StatusFor::<T>::get(h), None);
+			// Case 4: Requested by 10 becomes requested by 10
+			let (p, h) = preimage::<T>(65536);
+			assert_eq!(crate::PreimageFor::<T>::get(&(h, 65536)), Some(p));
+			assert_eq!(
+				crate::StatusFor::<T>::get(h),
+				Some(RequestStatus::Requested { deposit: None, count: 10, len: Some(65536) })
+			);
+		});
+	}
+
+	/// Returns a preimage with a given size and its hash.
+	fn preimage<T: Config>(
+		len: usize,
+	) -> (BoundedVec<u8, ConstU32<MAX_SIZE>>, <T as frame_system::Config>::Hash) {
+		let p = bounded_vec![1; len];
+		let h = <T as frame_system::Config>::Hashing::hash_of(&p);
+		(p, h)
+	}
+}
diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs
index e12598a35b4bbec4d8a2b2943f2b9b2d8bffe9e0..ce74ea65bd8aa1f93e8c41342873258f3137a8f5 100644
--- a/substrate/frame/preimage/src/mock.rs
+++ b/substrate/frame/preimage/src/mock.rs
@@ -105,7 +105,6 @@ impl Config for Test {
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type ManagerOrigin = EnsureSignedBy<One, u64>;
-	type MaxSize = ConstU32<1024>;
 	type BaseDeposit = ConstU64<2>;
 	type ByteDeposit = ConstU64<1>;
 }
diff --git a/substrate/frame/preimage/src/tests.rs b/substrate/frame/preimage/src/tests.rs
index e6b64ae16dd8c9115b107a377fdd003e3b6b7906..f480b9c36b6705634bcf308baae9183eeb2e4f13 100644
--- a/substrate/frame/preimage/src/tests.rs
+++ b/substrate/frame/preimage/src/tests.rs
@@ -17,11 +17,35 @@
 
 //! # Scheduler tests.
 
+#![cfg(test)]
+
 use super::*;
 use crate::mock::*;
 
-use frame_support::{assert_noop, assert_ok};
+use frame_support::{
+	assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec,
+	traits::{Bounded, BoundedInline, Hash as PreimageHash},
+	StorageNoopGuard,
+};
 use pallet_balances::Error as BalancesError;
+use sp_core::{blake2_256, H256};
+
+/// Returns one `Inline`, `Lookup` and `Legacy` item each with different data and hash.
+pub fn make_bounded_values() -> (Bounded<Vec<u8>>, Bounded<Vec<u8>>, Bounded<Vec<u8>>) {
+	let data: BoundedInline = bounded_vec![1];
+	let inline = Bounded::<Vec<u8>>::Inline(data);
+
+	let data = vec![1, 2];
+	let hash: H256 = blake2_256(&data[..]).into();
+	let len = data.len() as u32;
+	let lookup = Bounded::<Vec<u8>>::unrequested(hash, len);
+
+	let data = vec![1, 2, 3];
+	let hash: H256 = blake2_256(&data[..]).into();
+	let legacy = Bounded::<Vec<u8>>::Legacy { hash, dummy: Default::default() };
+
+	(inline, lookup, legacy)
+}
 
 #[test]
 fn user_note_preimage_works() {
@@ -56,10 +80,7 @@ fn manager_note_preimage_works() {
 		assert!(Preimage::have_preimage(&h));
 		assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
 
-		assert_noop!(
-			Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]),
-			Error::<Test>::AlreadyNoted
-		);
+		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
 	});
 }
 
@@ -130,14 +151,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() {
 	new_test_ext().execute_with(|| {
 		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
 		assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
-		assert_noop!(
-			Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])),
-			Error::<Test>::Requested
-		);
+		assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])));
+		// it's still here.
 
 		let h = hashed([1]);
 		assert!(Preimage::have_preimage(&h));
 		assert_eq!(Preimage::get_preimage(&h), Some(vec![1]));
+
+		// now it's gone
+		assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
+		assert!(!Preimage::have_preimage(&hashed([1])));
 	});
 }
 
@@ -145,15 +168,16 @@ fn requested_then_noted_preimage_cannot_be_unnoted() {
 fn request_note_order_makes_no_difference() {
 	let one_way = new_test_ext().execute_with(|| {
 		assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
-		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
+		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
 		(
 			StatusFor::<Test>::iter().collect::<Vec<_>>(),
 			PreimageFor::<Test>::iter().collect::<Vec<_>>(),
 		)
 	});
 	new_test_ext().execute_with(|| {
-		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1]));
+		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
 		assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
+		assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
 		let other_way = (
 			StatusFor::<Test>::iter().collect::<Vec<_>>(),
 			PreimageFor::<Test>::iter().collect::<Vec<_>>(),
@@ -189,6 +213,7 @@ fn request_user_note_order_makes_no_difference() {
 	new_test_ext().execute_with(|| {
 		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
 		assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
+		assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
 		let other_way = (
 			StatusFor::<Test>::iter().collect::<Vec<_>>(),
 			PreimageFor::<Test>::iter().collect::<Vec<_>>(),
@@ -226,8 +251,240 @@ fn user_noted_then_requested_preimage_is_refunded_once_only() {
 		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]));
 		assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1])));
 		assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])));
+		assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])));
 		// Still have reserve from `vec[1; 3]`.
 		assert_eq!(Balances::reserved_balance(2), 5);
 		assert_eq!(Balances::free_balance(2), 95);
 	});
 }
+
+#[test]
+fn noted_preimage_use_correct_map() {
+	new_test_ext().execute_with(|| {
+		// Add one preimage per bucket...
+		for i in 0..7 {
+			assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; 128 << (i * 2)]));
+		}
+		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; MAX_SIZE as usize]));
+		assert_eq!(PreimageFor::<Test>::iter().count(), 8);
+
+		// All are present
+		assert_eq!(StatusFor::<Test>::iter().count(), 8);
+
+		// Now start removing them again...
+		for i in 0..7 {
+			assert_ok!(Preimage::unnote_preimage(
+				RuntimeOrigin::signed(1),
+				hashed(vec![0; 128 << (i * 2)])
+			));
+		}
+		assert_eq!(PreimageFor::<Test>::iter().count(), 1);
+		assert_ok!(Preimage::unnote_preimage(
+			RuntimeOrigin::signed(1),
+			hashed(vec![0; MAX_SIZE as usize])
+		));
+		assert_eq!(PreimageFor::<Test>::iter().count(), 0);
+
+		// All are gone
+		assert_eq!(StatusFor::<Test>::iter().count(), 0);
+	});
+}
+
+/// The `StorePreimage` and `QueryPreimage` traits work together.
+#[test]
+fn query_and_store_preimage_workflow() {
+	new_test_ext().execute_with(|| {
+		let _guard = StorageNoopGuard::default();
+		let data: Vec<u8> = vec![1; 512];
+		let encoded = data.encode();
+
+		// Bound an unbound value.
+		let bound = Preimage::bound(data.clone()).unwrap();
+		let (len, hash) = (bound.len().unwrap(), bound.hash());
+
+		assert_eq!(hash, blake2_256(&encoded).into());
+		assert_eq!(bound.len(), Some(len));
+		assert!(bound.lookup_needed(), "Should not be Inlined");
+		assert_eq!(bound.lookup_len(), Some(len));
+
+		// The value is requested and available.
+		assert!(Preimage::is_requested(&hash));
+		assert!(<Preimage as QueryPreimage>::have(&bound));
+		assert_eq!(Preimage::len(&hash), Some(len));
+
+		// It can be fetched with length.
+		assert_eq!(Preimage::fetch(&hash, Some(len)).unwrap(), encoded);
+		// ... and without length.
+		assert_eq!(Preimage::fetch(&hash, None).unwrap(), encoded);
+		// ... but not with wrong length.
+		assert_err!(Preimage::fetch(&hash, Some(0)), DispatchError::Unavailable);
+
+		// It can be peeked and decoded correctly.
+		assert_eq!(Preimage::peek::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
+		// Request it two more times.
+		assert_eq!(Preimage::pick::<Vec<u8>>(hash, len), bound);
+		Preimage::request(&hash);
+		// It is requested thrice.
+		assert!(matches!(
+			StatusFor::<Test>::get(&hash).unwrap(),
+			RequestStatus::Requested { count: 3, .. }
+		));
+
+		// It can be realized and decoded correctly.
+		assert_eq!(Preimage::realize::<Vec<u8>>(&bound).unwrap(), (data.clone(), Some(len)));
+		assert!(matches!(
+			StatusFor::<Test>::get(&hash).unwrap(),
+			RequestStatus::Requested { count: 2, .. }
+		));
+		// Dropping should unrequest.
+		Preimage::drop(&bound);
+		assert!(matches!(
+			StatusFor::<Test>::get(&hash).unwrap(),
+			RequestStatus::Requested { count: 1, .. }
+		));
+
+		// Is still available.
+		assert!(<Preimage as QueryPreimage>::have(&bound));
+		// Manually unnote it.
+		Preimage::unnote(&hash);
+		// Is not available anymore.
+		assert!(!<Preimage as QueryPreimage>::have(&bound));
+		assert_err!(Preimage::fetch(&hash, Some(len)), DispatchError::Unavailable);
+		// And not requested since the traits assume permissioned origin.
+		assert!(!Preimage::is_requested(&hash));
+
+		// No storage changes remain. Checked by `StorageNoopGuard`.
+	});
+}
+
+/// The request function behaves as expected.
+#[test]
+fn query_preimage_request_works() {
+	new_test_ext().execute_with(|| {
+		let _guard = StorageNoopGuard::default();
+		let data: Vec<u8> = vec![1; 10];
+		let hash: PreimageHash = blake2_256(&data[..]).into();
+
+		// Request the preimage.
+		<Preimage as QueryPreimage>::request(&hash);
+
+		// The preimage is requested with unknown length and cannot be fetched.
+		assert!(<Preimage as QueryPreimage>::is_requested(&hash));
+		assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
+		assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
+
+		// Request again.
+		<Preimage as QueryPreimage>::request(&hash);
+		// The preimage is still requested.
+		assert!(<Preimage as QueryPreimage>::is_requested(&hash));
+		assert!(<Preimage as QueryPreimage>::len(&hash).is_none());
+		assert_noop!(<Preimage as QueryPreimage>::fetch(&hash, None), DispatchError::Unavailable);
+		// But there is only one entry in the map.
+		assert_eq!(StatusFor::<Test>::iter().count(), 1);
+
+		// Un-request the preimage.
+		<Preimage as QueryPreimage>::unrequest(&hash);
+		// It is still requested.
+		assert!(<Preimage as QueryPreimage>::is_requested(&hash));
+		// Un-request twice.
+		<Preimage as QueryPreimage>::unrequest(&hash);
+		// It is not requested anymore.
+		assert!(!<Preimage as QueryPreimage>::is_requested(&hash));
+		// And there is no entry in the map.
+		assert_eq!(StatusFor::<Test>::iter().count(), 0);
+	});
+}
+
+/// The `QueryPreimage` functions can be used together with `Bounded` values.
+#[test]
+fn query_preimage_hold_and_drop_work() {
+	new_test_ext().execute_with(|| {
+		let _guard = StorageNoopGuard::default();
+		let (inline, lookup, legacy) = make_bounded_values();
+
+		// `hold` does nothing for `Inline` values.
+		assert_storage_noop!(<Preimage as QueryPreimage>::hold(&inline));
+		// `hold` requests `Lookup` values.
+		<Preimage as QueryPreimage>::hold(&lookup);
+		assert!(<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
+		// `hold` requests `Legacy` values.
+		<Preimage as QueryPreimage>::hold(&legacy);
+		assert!(<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
+
+		// There are two values requested in total.
+		assert_eq!(StatusFor::<Test>::iter().count(), 2);
+
+		// Cleanup by dropping both.
+		<Preimage as QueryPreimage>::drop(&lookup);
+		assert!(!<Preimage as QueryPreimage>::is_requested(&lookup.hash()));
+		<Preimage as QueryPreimage>::drop(&legacy);
+		assert!(!<Preimage as QueryPreimage>::is_requested(&legacy.hash()));
+
+		// There are no values requested anymore.
+		assert_eq!(StatusFor::<Test>::iter().count(), 0);
+	});
+}
+
+/// The `StorePreimage` trait works as expected.
+#[test]
+fn store_preimage_basic_works() {
+	new_test_ext().execute_with(|| {
+		let _guard = StorageNoopGuard::default();
+		let data: Vec<u8> = vec![1; 512]; // Too large to inline.
+		let encoded = Cow::from(data.encode());
+
+		// Bound the data.
+		let bound = <Preimage as StorePreimage>::bound(data.clone()).unwrap();
+		// The preimage can be peeked.
+		assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
+		// Un-note the preimage.
+		<Preimage as StorePreimage>::unnote(&bound.hash());
+		// The preimage cannot be peeked anymore.
+		assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
+		// Noting the wrong pre-image does not make it peek-able.
+		assert_ok!(<Preimage as StorePreimage>::note(Cow::Borrowed(&data)));
+		assert_err!(<Preimage as QueryPreimage>::peek(&bound), DispatchError::Unavailable);
+
+		// Manually note the preimage makes it peek-able again.
+		assert_ok!(<Preimage as StorePreimage>::note(encoded.clone()));
+		// Noting again works.
+		assert_ok!(<Preimage as StorePreimage>::note(encoded));
+		assert_ok!(<Preimage as QueryPreimage>::peek(&bound));
+
+		// Cleanup.
+		<Preimage as StorePreimage>::unnote(&bound.hash());
+		let data_hash = blake2_256(&data);
+		<Preimage as StorePreimage>::unnote(&data_hash.into());
+
+		// No storage changes remain. Checked by `StorageNoopGuard`.
+	});
+}
+
+#[test]
+fn store_preimage_note_too_large_errors() {
+	new_test_ext().execute_with(|| {
+		// Works with `MAX_LENGTH`.
+		let len = <Preimage as StorePreimage>::MAX_LENGTH;
+		let data = vec![0u8; len];
+		assert_ok!(<Preimage as StorePreimage>::note(data.into()));
+
+		// Errors with `MAX_LENGTH+1`.
+		let data = vec![0u8; len + 1];
+		assert_err!(<Preimage as StorePreimage>::note(data.into()), DispatchError::Exhausted);
+	});
+}
+
+#[test]
+fn store_preimage_bound_too_large_errors() {
+	new_test_ext().execute_with(|| {
+		// Using `MAX_LENGTH` number of bytes in a vector does not work
+		// since SCALE prepends the length.
+		let len = <Preimage as StorePreimage>::MAX_LENGTH;
+		let data: Vec<u8> = vec![0; len];
+		assert_err!(<Preimage as StorePreimage>::bound(data.clone()), DispatchError::Exhausted);
+
+		// Works with `MAX_LENGTH-4`.
+		let data: Vec<u8> = vec![0; len - 4];
+		assert_ok!(<Preimage as StorePreimage>::bound(data.clone()));
+	});
+}
diff --git a/substrate/frame/preimage/src/weights.rs b/substrate/frame/preimage/src/weights.rs
index ad9e3e569e733e8263cbb811226e3d45889a72d6..186c41b798c6b9cd061a1f7067f512bb20aa5b55 100644
--- a/substrate/frame/preimage/src/weights.rs
+++ b/substrate/frame/preimage/src/weights.rs
@@ -18,22 +18,24 @@
 //! Autogenerated weights for pallet_preimage
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/substrate
+// /home/benchbot/cargo_target_dir/production/substrate
 // benchmark
 // pallet
-// --chain=dev
 // --steps=50
 // --repeat=20
-// --pallet=pallet_preimage
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
-// --template=./.maintain/frame-weight-template.hbs
+// --heap-pages=4096
+// --pallet=pallet_preimage
+// --chain=dev
 // --output=./frame/preimage/src/weights.rs
+// --template=./.maintain/frame-weight-template.hbs
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -61,88 +63,90 @@ pub trait WeightInfo {
 /// Weights for pallet_preimage using the Substrate node and recommended hardware.
 pub struct SubstrateWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
-	// Storage: Preimage PreimageFor (r:1 w:1)
 	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(32_591_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
+			.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:0)
+	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_requested_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(23_350_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
+			.saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64))
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
+			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:0)
+	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_no_deposit_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(21_436_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
+			.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
+			.saturating_add(T::DbWeight::get().reads(1 as u64))
+			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unnote_preimage() -> Weight {
-		Weight::from_ref_time(44_380_000 as u64)
+		Weight::from_ref_time(44_567_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unnote_no_deposit_preimage() -> Weight {
-		Weight::from_ref_time(30_280_000 as u64)
+		Weight::from_ref_time(30_065_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_preimage() -> Weight {
-		Weight::from_ref_time(42_809_000 as u64)
+		Weight::from_ref_time(28_470_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_no_deposit_preimage() -> Weight {
-		Weight::from_ref_time(28_964_000 as u64)
+		Weight::from_ref_time(14_601_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_unnoted_preimage() -> Weight {
-		Weight::from_ref_time(17_555_000 as u64)
+		Weight::from_ref_time(20_121_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_requested_preimage() -> Weight {
-		Weight::from_ref_time(7_745_000 as u64)
+		Weight::from_ref_time(9_440_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unrequest_preimage() -> Weight {
-		Weight::from_ref_time(29_758_000 as u64)
+		Weight::from_ref_time(29_013_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unrequest_unnoted_preimage() -> Weight {
-		Weight::from_ref_time(18_360_000 as u64)
+		Weight::from_ref_time(9_223_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
+			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn unrequest_multi_referenced_preimage() -> Weight {
-		Weight::from_ref_time(7_439_000 as u64)
+		Weight::from_ref_time(9_252_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
@@ -150,88 +154,90 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 
 // For backwards compatibility and tests
 impl WeightInfo for () {
-	// Storage: Preimage PreimageFor (r:1 w:1)
 	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(32_591_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
+			.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:0)
+	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_requested_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(23_350_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+			.saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64))
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
+			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:0)
+	// Storage: Preimage StatusFor (r:1 w:1)
+	// Storage: Preimage PreimageFor (r:0 w:1)
+	/// The range of component `s` is `[0, 4194304]`.
 	fn note_no_deposit_preimage(s: u32, ) -> Weight {
-		Weight::from_ref_time(0 as u64)
+		Weight::from_ref_time(21_436_000 as u64)
 			// Standard Error: 0
-			.saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+			.saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64))
+			.saturating_add(RocksDbWeight::get().reads(1 as u64))
+			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unnote_preimage() -> Weight {
-		Weight::from_ref_time(44_380_000 as u64)
+		Weight::from_ref_time(44_567_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unnote_no_deposit_preimage() -> Weight {
-		Weight::from_ref_time(30_280_000 as u64)
+		Weight::from_ref_time(30_065_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_preimage() -> Weight {
-		Weight::from_ref_time(42_809_000 as u64)
+		Weight::from_ref_time(28_470_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_no_deposit_preimage() -> Weight {
-		Weight::from_ref_time(28_964_000 as u64)
+		Weight::from_ref_time(14_601_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_unnoted_preimage() -> Weight {
-		Weight::from_ref_time(17_555_000 as u64)
+		Weight::from_ref_time(20_121_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn request_requested_preimage() -> Weight {
-		Weight::from_ref_time(7_745_000 as u64)
+		Weight::from_ref_time(9_440_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unrequest_preimage() -> Weight {
-		Weight::from_ref_time(29_758_000 as u64)
+		Weight::from_ref_time(29_013_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Preimage PreimageFor (r:0 w:1)
 	fn unrequest_unnoted_preimage() -> Weight {
-		Weight::from_ref_time(18_360_000 as u64)
+		Weight::from_ref_time(9_223_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes(2 as u64))
+			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Preimage StatusFor (r:1 w:1)
 	fn unrequest_multi_referenced_preimage() -> Weight {
-		Weight::from_ref_time(7_439_000 as u64)
+		Weight::from_ref_time(9_252_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
diff --git a/substrate/frame/recovery/src/lib.rs b/substrate/frame/recovery/src/lib.rs
index 0b6b7b0f51d9a5035ed96dca8d9fc0171b58a373..18d3d48dc024c72ed4ed826e587947b932dd7c79 100644
--- a/substrate/frame/recovery/src/lib.rs
+++ b/substrate/frame/recovery/src/lib.rs
@@ -452,7 +452,7 @@ pub mod pallet {
 			ensure!(!friends.is_empty(), Error::<T>::NotEnoughFriends);
 			ensure!(threshold as usize <= friends.len(), Error::<T>::NotEnoughFriends);
 			let bounded_friends: FriendsOf<T> =
-				friends.try_into().map_err(|()| Error::<T>::MaxFriends)?;
+				friends.try_into().map_err(|_| Error::<T>::MaxFriends)?;
 			ensure!(Self::is_sorted_and_unique(&bounded_friends), Error::<T>::NotSorted);
 			// Total deposit is base fee + number of friends * factor fee
 			let friend_deposit = T::FriendDepositFactor::get()
@@ -554,7 +554,7 @@ pub mod pallet {
 				Err(pos) => active_recovery
 					.friends
 					.try_insert(pos, who.clone())
-					.map_err(|()| Error::<T>::MaxFriends)?,
+					.map_err(|_| Error::<T>::MaxFriends)?,
 			}
 			// Update storage with the latest details
 			<ActiveRecoveries<T>>::insert(&lost, &rescuer, active_recovery);
diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs
index 45ec894e2c2c0312649daaebe6091eca6109b211..bc6fb31bf112786a535e159e151a0f505a00166a 100644
--- a/substrate/frame/referenda/src/benchmarking.rs
+++ b/substrate/frame/referenda/src/benchmarking.rs
@@ -24,10 +24,10 @@ use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account}
 use frame_support::{
 	assert_ok,
 	dispatch::UnfilteredDispatchable,
-	traits::{Currency, EnsureOrigin},
+	traits::{Bounded, Currency, EnsureOrigin},
 };
 use frame_system::RawOrigin;
-use sp_runtime::traits::{Bounded, Hash};
+use sp_runtime::traits::Bounded as ArithBounded;
 
 const SEED: u32 = 0;
 
@@ -42,6 +42,12 @@ fn funded_account<T: Config<I>, I: 'static>(name: &'static str, index: u32) -> T
 	caller
 }
 
+fn dummy_call<T: Config<I>, I: 'static>() -> Bounded<<T as Config<I>>::RuntimeCall> {
+	let inner = frame_system::Call::remark { remark: vec![] };
+	let call = <T as Config<I>>::RuntimeCall::from(inner);
+	T::Preimages::bound(call).unwrap()
+}
+
 fn create_referendum<T: Config<I>, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) {
 	let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin();
 	if let Ok(caller) = frame_system::ensure_signed(origin.clone()) {
@@ -50,9 +56,9 @@ fn create_referendum<T: Config<I>, I: 'static>() -> (T::RuntimeOrigin, Referendu
 	}
 
 	let proposal_origin = Box::new(RawOrigin::Root.into());
-	let proposal_hash = T::Hashing::hash_of(&0);
+	let proposal = dummy_call::<T, I>();
 	let enactment_moment = DispatchTime::After(0u32.into());
-	let call = Call::<T, I>::submit { proposal_origin, proposal_hash, enactment_moment };
+	let call = crate::Call::<T, I>::submit { proposal_origin, proposal, enactment_moment };
 	assert_ok!(call.dispatch_bypass_filter(origin.clone()));
 	let index = ReferendumCount::<T, I>::get() - 1;
 	(origin, index)
@@ -196,7 +202,7 @@ benchmarks_instance_pallet! {
 	}: _<T::RuntimeOrigin>(
 		origin,
 		Box::new(RawOrigin::Root.into()),
-		T::Hashing::hash_of(&0),
+		dummy_call::<T, I>(),
 		DispatchTime::After(0u32.into())
 	) verify {
 		let index = ReferendumCount::<T, I>::get().checked_sub(1).unwrap();
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index 739f0dbc30ed4781a65d2503a919e499e25d30b9..1bdc19d49c414cb06fb051856a2d59cd74a4abc5 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -69,11 +69,11 @@ use frame_support::{
 	ensure,
 	traits::{
 		schedule::{
-			v2::{Anon as ScheduleAnon, Named as ScheduleNamed},
-			DispatchTime, MaybeHashed,
+			v3::{Anon as ScheduleAnon, Named as ScheduleNamed},
+			DispatchTime,
 		},
-		Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling,
-		ReservableCurrency, VoteTally,
+		Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage,
+		ReservableCurrency, StorePreimage, VoteTally,
 	},
 	BoundedVec,
 };
@@ -92,10 +92,10 @@ use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch};
 pub use self::{
 	pallet::*,
 	types::{
-		BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted,
-		NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf,
-		ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo,
-		TrackInfoOf, TracksInfo, VotesOf,
+		BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit,
+		InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo,
+		ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf,
+		TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf,
 	},
 	weights::WeightInfo,
 };
@@ -149,23 +149,16 @@ pub mod pallet {
 		// System level stuff.
 		type RuntimeCall: Parameter
 			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
-			+ From<Call<Self, I>>;
+			+ From<Call<Self, I>>
+			+ IsType<<Self as frame_system::Config>::RuntimeCall>
+			+ From<frame_system::Call<Self>>;
 		type RuntimeEvent: From<Event<Self, I>>
 			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
 		/// Weight information for extrinsics in this pallet.
 		type WeightInfo: WeightInfo;
 		/// The Scheduler.
-		type Scheduler: ScheduleAnon<
-				Self::BlockNumber,
-				CallOf<Self, I>,
-				PalletsOriginOf<Self>,
-				Hash = Self::Hash,
-			> + ScheduleNamed<
-				Self::BlockNumber,
-				CallOf<Self, I>,
-				PalletsOriginOf<Self>,
-				Hash = Self::Hash,
-			>;
+		type Scheduler: ScheduleAnon<Self::BlockNumber, CallOf<Self, I>, PalletsOriginOf<Self>>
+			+ ScheduleNamed<Self::BlockNumber, CallOf<Self, I>, PalletsOriginOf<Self>>;
 		/// Currency type for this pallet.
 		type Currency: ReservableCurrency<Self::AccountId>;
 		// Origins and unbalances.
@@ -221,6 +214,9 @@ pub mod pallet {
 				Self::BlockNumber,
 				RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin,
 			>;
+
+		/// The preimage provider.
+		type Preimages: QueryPreimage + StorePreimage;
 	}
 
 	/// The next free referendum index, aka the number of referenda started so far.
@@ -259,8 +255,8 @@ pub mod pallet {
 			index: ReferendumIndex,
 			/// The track (and by extension proposal dispatch origin) of this referendum.
 			track: TrackIdOf<T, I>,
-			/// The hash of the proposal up for referendum.
-			proposal_hash: T::Hash,
+			/// The proposal for the referendum.
+			proposal: BoundedCallOf<T, I>,
 		},
 		/// The decision deposit has been placed.
 		DecisionDepositPlaced {
@@ -293,8 +289,8 @@ pub mod pallet {
 			index: ReferendumIndex,
 			/// The track (and by extension proposal dispatch origin) of this referendum.
 			track: TrackIdOf<T, I>,
-			/// The hash of the proposal up for referendum.
-			proposal_hash: T::Hash,
+			/// The proposal for the referendum.
+			proposal: BoundedCallOf<T, I>,
 			/// The current tally of votes in this referendum.
 			tally: T::Tally,
 		},
@@ -381,7 +377,7 @@ pub mod pallet {
 		/// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds
 		///   available.
 		/// - `proposal_origin`: The origin from which the proposal should be executed.
-		/// - `proposal_hash`: The hash of the proposal preimage.
+		/// - `proposal`: The proposal.
 		/// - `enactment_moment`: The moment that the proposal should be enacted.
 		///
 		/// Emits `Submitted`.
@@ -389,7 +385,7 @@ pub mod pallet {
 		pub fn submit(
 			origin: OriginFor<T>,
 			proposal_origin: Box<PalletsOriginOf<T>>,
-			proposal_hash: T::Hash,
+			proposal: BoundedCallOf<T, I>,
 			enactment_moment: DispatchTime<T::BlockNumber>,
 		) -> DispatchResult {
 			let who = T::SubmitOrigin::ensure_origin(origin)?;
@@ -403,11 +399,12 @@ pub mod pallet {
 				r
 			});
 			let now = frame_system::Pallet::<T>::block_number();
-			let nudge_call = Call::nudge_referendum { index };
+			let nudge_call =
+				T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
 			let status = ReferendumStatus {
 				track,
 				origin: *proposal_origin,
-				proposal_hash,
+				proposal: proposal.clone(),
 				enactment: enactment_moment,
 				submitted: now,
 				submission_deposit,
@@ -419,7 +416,7 @@ pub mod pallet {
 			};
 			ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
 
-			Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal_hash });
+			Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal });
 			Ok(())
 		}
 
@@ -651,7 +648,8 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
 		let mut status = ReferendumStatusOf::<T, I> {
 			track: class,
 			origin: frame_support::dispatch::RawOrigin::Root.into(),
-			proposal_hash: <T::Hashing as sp_runtime::traits::Hash>::hash_of(&index),
+			proposal: T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))
+				.map_err(|_| ())?,
 			enactment: DispatchTime::After(Zero::zero()),
 			submitted: now,
 			submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() },
@@ -709,18 +707,18 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		track: &TrackInfoOf<T, I>,
 		desired: DispatchTime<T::BlockNumber>,
 		origin: PalletsOriginOf<T>,
-		call_hash: T::Hash,
+		call: BoundedCallOf<T, I>,
 	) {
 		let now = frame_system::Pallet::<T>::block_number();
 		let earliest_allowed = now.saturating_add(track.min_enactment_period);
 		let desired = desired.evaluate(now);
 		let ok = T::Scheduler::schedule_named(
-			(ASSEMBLY_ID, "enactment", index).encode(),
+			(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
 			DispatchTime::At(desired.max(earliest_allowed)),
 			None,
 			63,
 			origin,
-			MaybeHashed::Hash(call_hash),
+			call,
 		)
 		.is_ok();
 		debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed");
@@ -728,7 +726,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 
 	/// Set an alarm to dispatch `call` at block number `when`.
 	fn set_alarm(
-		call: impl Into<CallOf<T, I>>,
+		call: BoundedCallOf<T, I>,
 		when: T::BlockNumber,
 	) -> Option<(T::BlockNumber, ScheduleAddressOf<T, I>)> {
 		let alarm_interval = T::AlarmInterval::get().max(One::one());
@@ -739,7 +737,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 			None,
 			128u8,
 			frame_system::RawOrigin::Root.into(),
-			MaybeHashed::Value(call.into()),
+			call,
 		)
 		.ok()
 		.map(|x| (when, x));
@@ -776,7 +774,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		Self::deposit_event(Event::<T, I>::DecisionStarted {
 			index,
 			tally: status.tally.clone(),
-			proposal_hash: status.proposal_hash,
+			proposal: status.proposal.clone(),
 			track: status.track,
 		});
 		let confirming = if is_passing {
@@ -843,12 +841,21 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		let alarm_interval = T::AlarmInterval::get().max(One::one());
 		let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval;
 
+		let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
+			track,
+		})) {
+			Ok(c) => c,
+			Err(_) => {
+				debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",);
+				return
+			},
+		};
 		let maybe_result = T::Scheduler::schedule(
 			DispatchTime::At(when),
 			None,
 			128u8,
 			frame_system::RawOrigin::Root.into(),
-			MaybeHashed::Value(Call::one_fewer_deciding { track }.into()),
+			call,
 		);
 		debug_assert!(
 			maybe_result.is_ok(),
@@ -871,7 +878,18 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
 			// Either no alarm or one that was different
 			Self::ensure_no_alarm(status);
-			status.alarm = Self::set_alarm(Call::nudge_referendum { index }, alarm);
+			let call =
+				match T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index })) {
+					Ok(c) => c,
+					Err(_) => {
+						debug_assert!(
+							false,
+							"Unable to create a bounded call from `nudge_referendum`??",
+						);
+						return false
+					},
+				};
+			status.alarm = Self::set_alarm(call, alarm);
 			true
 		} else {
 			false
@@ -987,14 +1005,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 							// Passed!
 							Self::ensure_no_alarm(&mut status);
 							Self::note_one_fewer_deciding(status.track);
-							let (desired, call_hash) = (status.enactment, status.proposal_hash);
-							Self::schedule_enactment(
-								index,
-								track,
-								desired,
-								status.origin,
-								call_hash,
-							);
+							let (desired, call) = (status.enactment, status.proposal);
+							Self::schedule_enactment(index, track, desired, status.origin, call);
 							Self::deposit_event(Event::<T, I>::Confirmed {
 								index,
 								tally: status.tally,
diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs
index 920e529bf05ca93e1ad5ae1d9c7e667830b3d368..c98fbf9a676b1e2dd65d1c90fdbd7e5c875bfbfe 100644
--- a/substrate/frame/referenda/src/mock.rs
+++ b/substrate/frame/referenda/src/mock.rs
@@ -24,7 +24,7 @@ use frame_support::{
 	assert_ok, ord_parameter_types, parameter_types,
 	traits::{
 		ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling,
-		PreimageRecipient, SortedMembers,
+		SortedMembers,
 	},
 	weights::Weight,
 };
@@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy};
 use sp_core::H256;
 use sp_runtime::{
 	testing::Header,
-	traits::{BlakeTwo256, Hash, IdentityLookup},
+	traits::{BlakeTwo256, IdentityLookup},
 	DispatchResult, Perbill,
 };
 
@@ -97,7 +97,6 @@ impl pallet_preimage::Config for Test {
 	type WeightInfo = ();
 	type Currency = Balances;
 	type ManagerOrigin = EnsureRoot<u64>;
-	type MaxSize = ConstU32<4096>;
 	type BaseDeposit = ();
 	type ByteDeposit = ();
 }
@@ -111,8 +110,7 @@ impl pallet_scheduler::Config for Test {
 	type MaxScheduledPerBlock = ConstU32<100>;
 	type WeightInfo = ();
 	type OriginPrivilegeCmp = EqualPrivilegeOnly;
-	type PreimageProvider = Preimage;
-	type NoPreimagePostponement = ConstU64<10>;
+	type Preimages = Preimage;
 }
 impl pallet_balances::Config for Test {
 	type MaxReserves = ();
@@ -229,6 +227,7 @@ impl Config for Test {
 	type UndecidingTimeout = ConstU64<20>;
 	type AlarmInterval = AlarmInterval;
 	type Tracks = TestTracksInfo;
+	type Preimages = Preimage;
 }
 
 pub fn new_test_ext() -> sp_io::TestExternalities {
@@ -306,14 +305,13 @@ pub fn set_balance_proposal(value: u64) -> Vec<u8> {
 	.encode()
 }
 
-pub fn set_balance_proposal_hash(value: u64) -> H256 {
+pub fn set_balance_proposal_bounded(value: u64) -> BoundedCallOf<Test, ()> {
 	let c = RuntimeCall::Balances(pallet_balances::Call::set_balance {
 		who: 42,
 		new_free: value,
 		new_reserved: 0,
 	});
-	<Preimage as PreimageRecipient<_>>::note_preimage(c.encode().try_into().unwrap());
-	BlakeTwo256::hash_of(&c)
+	<Preimage as StorePreimage>::bound(c).unwrap()
 }
 
 #[allow(dead_code)]
@@ -321,7 +319,7 @@ pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult {
 	Referenda::submit(
 		RuntimeOrigin::signed(who),
 		Box::new(frame_system::RawOrigin::Root.into()),
-		set_balance_proposal_hash(value),
+		set_balance_proposal_bounded(value),
 		DispatchTime::After(delay),
 	)
 }
@@ -449,7 +447,7 @@ impl RefState {
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(frame_support::dispatch::RawOrigin::Root.into()),
-			set_balance_proposal_hash(1),
+			set_balance_proposal_bounded(1),
 			DispatchTime::At(10),
 		));
 		assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0));
diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs
index 778d00e5166936064d69e42efadc26ded1adecc5..355ce3021b87f8e278ed161afac84a80e1b9ba68 100644
--- a/substrate/frame/referenda/src/tests.rs
+++ b/substrate/frame/referenda/src/tests.rs
@@ -44,7 +44,7 @@ fn basic_happy_path_works() {
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
-			set_balance_proposal_hash(1),
+			set_balance_proposal_bounded(1),
 			DispatchTime::At(10),
 		));
 		assert_eq!(Balances::reserved_balance(&1), 2);
@@ -175,7 +175,7 @@ fn queueing_works() {
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(5),
 			Box::new(RawOrigin::Root.into()),
-			set_balance_proposal_hash(0),
+			set_balance_proposal_bounded(0),
 			DispatchTime::After(0),
 		));
 		assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(5), 0));
@@ -187,7 +187,7 @@ fn queueing_works() {
 			assert_ok!(Referenda::submit(
 				RuntimeOrigin::signed(i),
 				Box::new(RawOrigin::Root.into()),
-				set_balance_proposal_hash(i),
+				set_balance_proposal_bounded(i),
 				DispatchTime::After(0),
 			));
 			assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(i), i as u32));
@@ -272,7 +272,7 @@ fn auto_timeout_should_happen_with_nothing_but_submit() {
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
-			set_balance_proposal_hash(1),
+			set_balance_proposal_bounded(1),
 			DispatchTime::At(20),
 		));
 		run_to(20);
@@ -292,13 +292,13 @@ fn tracks_are_distinguished() {
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
-			set_balance_proposal_hash(1),
+			set_balance_proposal_bounded(1),
 			DispatchTime::At(10),
 		));
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(2),
 			Box::new(RawOrigin::None.into()),
-			set_balance_proposal_hash(2),
+			set_balance_proposal_bounded(2),
 			DispatchTime::At(20),
 		));
 
@@ -315,7 +315,7 @@ fn tracks_are_distinguished() {
 					ReferendumInfo::Ongoing(ReferendumStatus {
 						track: 0,
 						origin: OriginCaller::system(RawOrigin::Root),
-						proposal_hash: set_balance_proposal_hash(1),
+						proposal: set_balance_proposal_bounded(1),
 						enactment: DispatchTime::At(10),
 						submitted: 1,
 						submission_deposit: Deposit { who: 1, amount: 2 },
@@ -331,7 +331,7 @@ fn tracks_are_distinguished() {
 					ReferendumInfo::Ongoing(ReferendumStatus {
 						track: 1,
 						origin: OriginCaller::system(RawOrigin::None),
-						proposal_hash: set_balance_proposal_hash(2),
+						proposal: set_balance_proposal_bounded(2),
 						enactment: DispatchTime::At(20),
 						submitted: 1,
 						submission_deposit: Deposit { who: 2, amount: 2 },
@@ -350,13 +350,13 @@ fn tracks_are_distinguished() {
 #[test]
 fn submit_errors_work() {
 	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		// No track for Signed origins.
 		assert_noop!(
 			Referenda::submit(
 				RuntimeOrigin::signed(1),
 				Box::new(RawOrigin::Signed(2).into()),
-				h,
+				h.clone(),
 				DispatchTime::At(10),
 			),
 			Error::<Test>::NoTrack
@@ -381,7 +381,7 @@ fn decision_deposit_errors_work() {
 		let e = Error::<Test>::NotOngoing;
 		assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e);
 
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
@@ -403,7 +403,7 @@ fn refund_deposit_works() {
 		let e = Error::<Test>::BadReferendum;
 		assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(1), 0), e);
 
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
@@ -425,7 +425,7 @@ fn refund_deposit_works() {
 #[test]
 fn cancel_works() {
 	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
@@ -444,7 +444,7 @@ fn cancel_works() {
 #[test]
 fn cancel_errors_works() {
 	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
@@ -462,7 +462,7 @@ fn cancel_errors_works() {
 #[test]
 fn kill_works() {
 	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
@@ -482,7 +482,7 @@ fn kill_works() {
 #[test]
 fn kill_errors_works() {
 	new_test_ext().execute_with(|| {
-		let h = set_balance_proposal_hash(1);
+		let h = set_balance_proposal_bounded(1);
 		assert_ok!(Referenda::submit(
 			RuntimeOrigin::signed(1),
 			Box::new(RawOrigin::Root.into()),
diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs
index a6311e5f925be6333a120fe360a25c948bbc0162..2ce93cb6adc3ca725d73f21957ae68f74f33eee0 100644
--- a/substrate/frame/referenda/src/types.rs
+++ b/substrate/frame/referenda/src/types.rs
@@ -19,7 +19,10 @@
 
 use super::*;
 use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
-use frame_support::{traits::schedule::Anon, Parameter};
+use frame_support::{
+	traits::{schedule::v3::Anon, Bounded},
+	Parameter,
+};
 use scale_info::TypeInfo;
 use sp_arithmetic::{Rounding::*, SignedRounding::*};
 use sp_runtime::{FixedI64, PerThing, RuntimeDebug};
@@ -31,6 +34,7 @@ pub type NegativeImbalanceOf<T, I> = <<T as Config<I>>::Currency as Currency<
 	<T as frame_system::Config>::AccountId,
 >>::NegativeImbalance;
 pub type CallOf<T, I> = <T as Config<I>>::RuntimeCall;
+pub type BoundedCallOf<T, I> = Bounded<<T as Config<I>>::RuntimeCall>;
 pub type VotesOf<T, I> = <T as Config<I>>::Votes;
 pub type TallyOf<T, I> = <T as Config<I>>::Tally;
 pub type PalletsOriginOf<T> =
@@ -39,7 +43,7 @@ pub type ReferendumInfoOf<T, I> = ReferendumInfo<
 	TrackIdOf<T, I>,
 	PalletsOriginOf<T>,
 	<T as frame_system::Config>::BlockNumber,
-	<T as frame_system::Config>::Hash,
+	BoundedCallOf<T, I>,
 	BalanceOf<T, I>,
 	TallyOf<T, I>,
 	<T as frame_system::Config>::AccountId,
@@ -49,7 +53,7 @@ pub type ReferendumStatusOf<T, I> = ReferendumStatus<
 	TrackIdOf<T, I>,
 	PalletsOriginOf<T>,
 	<T as frame_system::Config>::BlockNumber,
-	<T as frame_system::Config>::Hash,
+	BoundedCallOf<T, I>,
 	BalanceOf<T, I>,
 	TallyOf<T, I>,
 	<T as frame_system::Config>::AccountId,
@@ -160,7 +164,7 @@ pub struct ReferendumStatus<
 	TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
-	Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
+	Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
@@ -171,7 +175,7 @@ pub struct ReferendumStatus<
 	/// The origin for this referendum.
 	pub(crate) origin: RuntimeOrigin,
 	/// The hash of the proposal up for referendum.
-	pub(crate) proposal_hash: Hash,
+	pub(crate) proposal: Call,
 	/// The time the proposal should be scheduled for enactment.
 	pub(crate) enactment: DispatchTime<Moment>,
 	/// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it
@@ -197,7 +201,7 @@ pub enum ReferendumInfo<
 	TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
-	Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
+	Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 	AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
@@ -209,7 +213,7 @@ pub enum ReferendumInfo<
 			TrackId,
 			RuntimeOrigin,
 			Moment,
-			Hash,
+			Call,
 			Balance,
 			Tally,
 			AccountId,
@@ -232,12 +236,12 @@ impl<
 		TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike,
-		Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
+		Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
 		ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone,
-	> ReferendumInfo<TrackId, RuntimeOrigin, Moment, Hash, Balance, Tally, AccountId, ScheduleAddress>
+	> ReferendumInfo<TrackId, RuntimeOrigin, Moment, Call, Balance, Tally, AccountId, ScheduleAddress>
 {
 	/// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not
 	/// in a valid state for the Decision Deposit to be refunded.
diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs
index 9397c66170425367f62352531ff9c19ac5134b90..aaa30fd88ffda53406ef49732d448cb7c7b824a9 100644
--- a/substrate/frame/scheduler/src/benchmarking.rs
+++ b/substrate/frame/scheduler/src/benchmarking.rs
@@ -18,201 +18,219 @@
 //! Scheduler pallet benchmarking.
 
 use super::*;
-use frame_benchmarking::benchmarks;
+use frame_benchmarking::{account, benchmarks};
 use frame_support::{
 	ensure,
-	traits::{OnInitialize, PreimageProvider, PreimageRecipient},
+	traits::{schedule::Priority, BoundedInline},
 };
-use sp_runtime::traits::Hash;
+use frame_system::RawOrigin;
 use sp_std::{prelude::*, vec};
 
 use crate::Pallet as Scheduler;
-use frame_system::Pallet as System;
+use frame_system::Call as SystemCall;
+
+const SEED: u32 = 0;
 
 const BLOCK_NUMBER: u32 = 2;
 
 type SystemOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
 
-/// Add `n` named items to the schedule.
+/// Add `n` items to the schedule.
 ///
 /// For `resolved`:
+/// - `
 /// - `None`: aborted (hash without preimage)
 /// - `Some(true)`: hash resolves into call if possible, plain call otherwise
 /// - `Some(false)`: plain call
-fn fill_schedule<T: Config>(
-	when: T::BlockNumber,
-	n: u32,
+fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {
+	let t = DispatchTime::At(when);
+	let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();
+	for i in 0..n {
+		let call = make_call::<T>(None);
+		let period = Some(((i + 100).into(), 100));
+		let name = u32_to_name(i);
+		Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;
+	}
+	ensure!(Agenda::<T>::get(when).len() == n as usize, "didn't fill schedule");
+	Ok(())
+}
+
+fn u32_to_name(i: u32) -> TaskName {
+	i.using_encoded(blake2_256)
+}
+
+fn make_task<T: Config>(
 	periodic: bool,
 	named: bool,
-	resolved: Option<bool>,
-) -> Result<(), &'static str> {
-	for i in 0..n {
-		// Named schedule is strictly heavier than anonymous
-		let (call, hash) = call_and_hash::<T>(i);
-		let call_or_hash = match resolved {
-			Some(true) => {
-				T::PreimageProvider::note_preimage(call.encode().try_into().unwrap());
-				if T::PreimageProvider::have_preimage(&hash) {
-					CallOrHashOf::<T>::Hash(hash)
-				} else {
-					call.into()
-				}
+	signed: bool,
+	maybe_lookup_len: Option<u32>,
+	priority: Priority,
+) -> ScheduledOf<T> {
+	let call = make_call::<T>(maybe_lookup_len);
+	let maybe_periodic = match periodic {
+		true => Some((100u32.into(), 100)),
+		false => None,
+	};
+	let maybe_id = match named {
+		true => Some(u32_to_name(0)),
+		false => None,
+	};
+	let origin = make_origin::<T>(signed);
+	Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData }
+}
+
+fn bounded<T: Config>(len: u32) -> Option<Bounded<<T as Config>::RuntimeCall>> {
+	let call =
+		<<T as Config>::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] });
+	T::Preimages::bound(call).ok()
+}
+
+fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> Bounded<<T as Config>::RuntimeCall> {
+	let bound = BoundedInline::bound() as u32;
+	let mut len = match maybe_lookup_len {
+		Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3,
+		None => bound.saturating_sub(4),
+	};
+
+	loop {
+		let c = match bounded::<T>(len) {
+			Some(x) => x,
+			None => {
+				len -= 1;
+				continue
 			},
-			Some(false) => call.into(),
-			None => CallOrHashOf::<T>::Hash(hash),
 		};
-		let period = match periodic {
-			true => Some(((i + 100).into(), 100)),
-			false => None,
-		};
-		let t = DispatchTime::At(when);
-		let origin = frame_system::RawOrigin::Root.into();
-		if named {
-			Scheduler::<T>::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?;
+		if c.lookup_needed() == maybe_lookup_len.is_some() {
+			break c
+		}
+		if maybe_lookup_len.is_some() {
+			len += 1;
 		} else {
-			Scheduler::<T>::do_schedule(t, period, 0, origin, call_or_hash)?;
+			if len > 0 {
+				len -= 1;
+			} else {
+				break c
+			}
 		}
 	}
-	ensure!(Agenda::<T>::get(when).len() == n as usize, "didn't fill schedule");
-	Ok(())
 }
 
-fn call_and_hash<T: Config>(i: u32) -> (<T as Config>::RuntimeCall, T::Hash) {
-	// Essentially a no-op call.
-	let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: i.encode() }.into();
-	let hash = T::Hashing::hash_of(&call);
-	(call, hash)
+fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {
+	match signed {
+		true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(),
+		false => frame_system::RawOrigin::Root.into(),
+	}
+}
+
+fn dummy_counter() -> WeightCounter {
+	WeightCounter { used: Weight::zero(), limit: Weight::MAX }
 }
 
 benchmarks! {
-	on_initialize_periodic_named_resolved {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, true, true, Some(true))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s * 2);
-		for i in 0..s {
-			assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
-		}
+	// `service_agendas` when no work is done.
+	service_agendas_base {
+		let now = T::BlockNumber::from(BLOCK_NUMBER);
+		IncompleteSince::<T>::put(now - One::one());
+	}: {
+		Scheduler::<T>::service_agendas(&mut dummy_counter(), now, 0);
+	} verify {
+		assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));
 	}
 
-	on_initialize_named_resolved {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, true, Some(true))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s * 2);
-		assert!(Agenda::<T>::iter().count() == 0);
+	// `service_agenda` when no work is done.
+	service_agenda_base {
+		let now = BLOCK_NUMBER.into();
+		let s in 0 .. T::MaxScheduledPerBlock::get();
+		fill_schedule::<T>(now, s)?;
+		let mut executed = 0;
+	}: {
+		Scheduler::<T>::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0);
+	} verify {
+		assert_eq!(executed, 0);
 	}
 
-	on_initialize_periodic_resolved {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, true, false, Some(true))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s * 2);
-		for i in 0..s {
-			assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
-		}
+	// `service_task` when the task is a non-periodic, non-named, non-fetched call which is not
+	// dispatched (e.g. due to being overweight).
+	service_task_base {
+		let now = BLOCK_NUMBER.into();
+		let task = make_task::<T>(false, false, false, None, 0);
+		// prevent any tasks from actually being executed as we only want the surrounding weight.
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
+	}: {
+		let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
+	} verify {
+		//assert_eq!(result, Ok(()));
 	}
 
-	on_initialize_resolved {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, false, Some(true))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s * 2);
-		assert!(Agenda::<T>::iter().count() == 0);
+	// `service_task` when the task is a non-periodic, non-named, fetched call (with a known
+	// preimage length) and which is not dispatched (e.g. due to being overweight).
+	service_task_fetched {
+		let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32);
+		let now = BLOCK_NUMBER.into();
+		let task = make_task::<T>(false, false, false, Some(s), 0);
+		// prevent any tasks from actually being executed as we only want the surrounding weight.
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
+	}: {
+		let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
+	} verify {
 	}
 
-	on_initialize_named_aborted {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, true, None)?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), 0);
-		if let Some(delay) = T::NoPreimagePostponement::get() {
-			assert_eq!(Agenda::<T>::get(when + delay).len(), s as usize);
-		} else {
-			assert!(Agenda::<T>::iter().count() == 0);
-		}
+	// `service_task` when the task is a non-periodic, named, non-fetched call which is not
+	// dispatched (e.g. due to being overweight).
+	service_task_named {
+		let now = BLOCK_NUMBER.into();
+		let task = make_task::<T>(false, true, false, None, 0);
+		// prevent any tasks from actually being executed as we only want the surrounding weight.
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
+	}: {
+		let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
+	} verify {
 	}
 
-	on_initialize_aborted {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, false, None)?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), 0);
-		if let Some(delay) = T::NoPreimagePostponement::get() {
-			assert_eq!(Agenda::<T>::get(when + delay).len(), s as usize);
-		} else {
-			assert!(Agenda::<T>::iter().count() == 0);
-		}
+	// `service_task` when the task is a periodic, non-named, non-fetched call which is not
+	// dispatched (e.g. due to being overweight).
+	service_task_periodic {
+		let now = BLOCK_NUMBER.into();
+		let task = make_task::<T>(true, false, false, None, 0);
+		// prevent any tasks from actually being executed as we only want the surrounding weight.
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };
+	}: {
+		let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);
+	} verify {
 	}
 
-	on_initialize_periodic_named {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, true, true, Some(false))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s);
-		for i in 0..s {
-			assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
-		}
+	// `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.
+	execute_dispatch_signed {
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
+		let origin = make_origin::<T>(true);
+		let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;
+	}: {
+		assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());
 	}
-
-	on_initialize_periodic {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, true, false, Some(false))?;
-	}: { Scheduler::<T>::on_initialize(when); }
 	verify {
-		assert_eq!(System::<T>::event_count(), s);
-		for i in 0..s {
-			assert_eq!(Agenda::<T>::get(when + (i + 100).into()).len(), 1 as usize);
-		}
 	}
 
-	on_initialize_named {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, true, Some(false))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
-	verify {
-		assert_eq!(System::<T>::event_count(), s);
-		assert!(Agenda::<T>::iter().count() == 0);
+	// `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.
+	execute_dispatch_unsigned {
+		let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
+		let origin = make_origin::<T>(false);
+		let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;
+	}: {
+		assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());
 	}
-
-	on_initialize {
-		let s in 1 .. T::MaxScheduledPerBlock::get();
-		let when = BLOCK_NUMBER.into();
-		fill_schedule::<T>(when, s, false, false, Some(false))?;
-	}: { Scheduler::<T>::on_initialize(BLOCK_NUMBER.into()); }
 	verify {
-		assert_eq!(System::<T>::event_count(), s);
-		assert!(Agenda::<T>::iter().count() == 0);
 	}
 
 	schedule {
-		let s in 0 .. T::MaxScheduledPerBlock::get();
+		let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
 		let when = BLOCK_NUMBER.into();
 		let periodic = Some((T::BlockNumber::one(), 100));
 		let priority = 0;
 		// Essentially a no-op call.
-		let inner_call = frame_system::Call::set_storage { items: vec![] }.into();
-		let call = Box::new(CallOrHashOf::<T>::Value(inner_call));
+		let call = Box::new(SystemCall::set_storage { items: vec![] }.into());
 
-		fill_schedule::<T>(when, s, true, true, Some(false))?;
-		let schedule_origin = T::ScheduleOrigin::successful_origin();
-	}: _<SystemOrigin<T>>(schedule_origin, when, periodic, priority, call)
+		fill_schedule::<T>(when, s)?;
+	}: _(RawOrigin::Root, when, periodic, priority, call)
 	verify {
 		ensure!(
 			Agenda::<T>::get(when).len() == (s + 1) as usize,
@@ -224,13 +242,13 @@ benchmarks! {
 		let s in 1 .. T::MaxScheduledPerBlock::get();
 		let when = BLOCK_NUMBER.into();
 
-		fill_schedule::<T>(when, s, true, true, Some(false))?;
+		fill_schedule::<T>(when, s)?;
 		assert_eq!(Agenda::<T>::get(when).len(), s as usize);
 		let schedule_origin = T::ScheduleOrigin::successful_origin();
 	}: _<SystemOrigin<T>>(schedule_origin, when, 0)
 	verify {
 		ensure!(
-			Lookup::<T>::get(0.encode()).is_none(),
+			Lookup::<T>::get(u32_to_name(0)).is_none(),
 			"didn't remove from lookup"
 		);
 		// Removed schedule is NONE
@@ -241,18 +259,16 @@ benchmarks! {
 	}
 
 	schedule_named {
-		let s in 0 .. T::MaxScheduledPerBlock::get();
-		let id = s.encode();
+		let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
+		let id = u32_to_name(s);
 		let when = BLOCK_NUMBER.into();
 		let periodic = Some((T::BlockNumber::one(), 100));
 		let priority = 0;
 		// Essentially a no-op call.
-		let inner_call = frame_system::Call::set_storage { items: vec![] }.into();
-		let call = Box::new(CallOrHashOf::<T>::Value(inner_call));
+		let call = Box::new(SystemCall::set_storage { items: vec![] }.into());
 
-		fill_schedule::<T>(when, s, true, true, Some(false))?;
-		let schedule_origin = T::ScheduleOrigin::successful_origin();
-	}: _<SystemOrigin<T>>(schedule_origin, id, when, periodic, priority, call)
+		fill_schedule::<T>(when, s)?;
+	}: _(RawOrigin::Root, id, when, periodic, priority, call)
 	verify {
 		ensure!(
 			Agenda::<T>::get(when).len() == (s + 1) as usize,
@@ -264,12 +280,11 @@ benchmarks! {
 		let s in 1 .. T::MaxScheduledPerBlock::get();
 		let when = BLOCK_NUMBER.into();
 
-		fill_schedule::<T>(when, s, true, true, Some(false))?;
-		let schedule_origin = T::ScheduleOrigin::successful_origin();
-	}: _<SystemOrigin<T>>(schedule_origin, 0.encode())
+		fill_schedule::<T>(when, s)?;
+	}: _(RawOrigin::Root, u32_to_name(0))
 	verify {
 		ensure!(
-			Lookup::<T>::get(0.encode()).is_none(),
+			Lookup::<T>::get(u32_to_name(0)).is_none(),
 			"didn't remove from lookup"
 		);
 		// Removed schedule is NONE
diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs
index 143fa37a9261dcd945c2f4fa04cd6c4869cb9b30..b5ea0deeba9a3ff91bfc81fae62bbce5b252d417 100644
--- a/substrate/frame/scheduler/src/lib.rs
+++ b/substrate/frame/scheduler/src/lib.rs
@@ -52,27 +52,33 @@
 
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
+pub mod migration;
 #[cfg(test)]
 mod mock;
 #[cfg(test)]
 mod tests;
 pub mod weights;
 
-use codec::{Codec, Decode, Encode};
+use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::{
-	dispatch::{DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter},
+	dispatch::{
+		DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, RawOrigin,
+	},
+	ensure,
 	traits::{
 		schedule::{self, DispatchTime, MaybeHashed},
-		EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, StorageVersion,
+		Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait,
+		PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage,
 	},
 	weights::Weight,
 };
-use frame_system::{self as system, ensure_signed};
+use frame_system::{self as system};
 pub use pallet::*;
 use scale_info::TypeInfo;
+use sp_io::hashing::blake2_256;
 use sp_runtime::{
 	traits::{BadOrigin, One, Saturating, Zero},
-	RuntimeDebug,
+	BoundedVec, RuntimeDebug,
 };
 use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*};
 pub use weights::WeightInfo;
@@ -96,24 +102,25 @@ struct ScheduledV1<Call, BlockNumber> {
 
 /// Information regarding an item to be executed in the future.
 #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]
-#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)]
-pub struct ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId> {
+#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
+pub struct Scheduled<Name, Call, BlockNumber, PalletsOrigin, AccountId> {
 	/// The unique identity for this task, if there is one.
-	maybe_id: Option<Vec<u8>>,
+	maybe_id: Option<Name>,
 	/// This task's priority.
 	priority: schedule::Priority,
 	/// The call to be dispatched.
 	call: Call,
 	/// If the call is periodic, then this points to the information concerning that.
 	maybe_periodic: Option<schedule::Period<BlockNumber>>,
-	/// The origin to dispatch the call.
+	/// The origin with which to dispatch the call.
 	origin: PalletsOrigin,
 	_phantom: PhantomData<AccountId>,
 }
 
-use crate::ScheduledV3 as ScheduledV2;
+use crate::{Scheduled as ScheduledV3, Scheduled as ScheduledV2};
 
-pub type ScheduledV2Of<T> = ScheduledV3<
+pub type ScheduledV2Of<T> = ScheduledV2<
+	Vec<u8>,
 	<T as Config>::RuntimeCall,
 	<T as frame_system::Config>::BlockNumber,
 	<T as Config>::PalletsOrigin,
@@ -121,57 +128,54 @@ pub type ScheduledV2Of<T> = ScheduledV3<
 >;
 
 pub type ScheduledV3Of<T> = ScheduledV3<
+	Vec<u8>,
 	CallOrHashOf<T>,
 	<T as frame_system::Config>::BlockNumber,
 	<T as Config>::PalletsOrigin,
 	<T as frame_system::Config>::AccountId,
 >;
 
-pub type ScheduledOf<T> = ScheduledV3Of<T>;
-
-/// The current version of Scheduled struct.
-pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =
-	ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId>;
+pub type ScheduledOf<T> = Scheduled<
+	TaskName,
+	Bounded<<T as Config>::RuntimeCall>,
+	<T as frame_system::Config>::BlockNumber,
+	<T as Config>::PalletsOrigin,
+	<T as frame_system::Config>::AccountId,
+>;
 
-#[cfg(feature = "runtime-benchmarks")]
-mod preimage_provider {
-	use frame_support::traits::PreimageRecipient;
-	pub trait PreimageProviderAndMaybeRecipient<H>: PreimageRecipient<H> {}
-	impl<H, T: PreimageRecipient<H>> PreimageProviderAndMaybeRecipient<H> for T {}
+struct WeightCounter {
+	used: Weight,
+	limit: Weight,
 }
-
-#[cfg(not(feature = "runtime-benchmarks"))]
-mod preimage_provider {
-	use frame_support::traits::PreimageProvider;
-	pub trait PreimageProviderAndMaybeRecipient<H>: PreimageProvider<H> {}
-	impl<H, T: PreimageProvider<H>> PreimageProviderAndMaybeRecipient<H> for T {}
+impl WeightCounter {
+	fn check_accrue(&mut self, w: Weight) -> bool {
+		let test = self.used.saturating_add(w);
+		if test.any_gt(self.limit) {
+			false
+		} else {
+			self.used = test;
+			true
+		}
+	}
+	fn can_accrue(&mut self, w: Weight) -> bool {
+		self.used.saturating_add(w).all_lte(self.limit)
+	}
 }
 
-pub use preimage_provider::PreimageProviderAndMaybeRecipient;
-
 pub(crate) trait MarginalWeightInfo: WeightInfo {
-	fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {
-		match (periodic, named, resolved) {
-			(_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1),
-			(_, true, None) =>
-				Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1),
-			(false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1),
-			(false, true, Some(false)) =>
-				Self::on_initialize_named(2) - Self::on_initialize_named(1),
-			(true, false, Some(false)) =>
-				Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1),
-			(true, true, Some(false)) =>
-				Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1),
-			(false, false, Some(true)) =>
-				Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1),
-			(false, true, Some(true)) =>
-				Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1),
-			(true, false, Some(true)) =>
-				Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1),
-			(true, true, Some(true)) =>
-				Self::on_initialize_periodic_named_resolved(2) -
-					Self::on_initialize_periodic_named_resolved(1),
+	fn service_task(maybe_lookup_len: Option<usize>, named: bool, periodic: bool) -> Weight {
+		let base = Self::service_task_base();
+		let mut total = match maybe_lookup_len {
+			None => base,
+			Some(l) => Self::service_task_fetched(l as u32),
+		};
+		if named {
+			total.saturating_accrue(Self::service_task_named().saturating_sub(base));
 		}
+		if periodic {
+			total.saturating_accrue(Self::service_task_periodic().saturating_sub(base));
+		}
+		total
 	}
 }
 impl<T: WeightInfo> MarginalWeightInfo for T {}
@@ -179,11 +183,7 @@ impl<T: WeightInfo> MarginalWeightInfo for T {}
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_support::{
-		dispatch::PostDispatchInfo,
-		pallet_prelude::*,
-		traits::{schedule::LookupError, PreimageProvider},
-	};
+	use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*};
 	use frame_system::pallet_prelude::*;
 
 	/// The current storage version.
@@ -192,7 +192,6 @@ pub mod pallet {
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
 	#[pallet::storage_version(STORAGE_VERSION)]
-	#[pallet::without_storage_info]
 	pub struct Pallet<T>(_);
 
 	/// `system::Config` should always be included in our implied traits.
@@ -207,7 +206,9 @@ pub mod pallet {
 			+ IsType<<Self as system::Config>::RuntimeOrigin>;
 
 		/// The caller origin, overarching type of all pallets origins.
-		type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq + TypeInfo;
+		type PalletsOrigin: From<system::RawOrigin<Self::AccountId>>
+			+ CallerTrait<Self::AccountId>
+			+ MaxEncodedLen;
 
 		/// The aggregated call type.
 		type RuntimeCall: Parameter
@@ -217,8 +218,7 @@ pub mod pallet {
 			> + GetDispatchInfo
 			+ From<system::Call<Self>>;
 
-		/// The maximum weight that may be scheduled per block for any dispatchables of less
-		/// priority than `schedule::HARD_DEADLINE`.
+		/// The maximum weight that may be scheduled per block for any dispatchables.
 		#[pallet::constant]
 		type MaximumWeight: Get<Weight>;
 
@@ -235,7 +235,6 @@ pub mod pallet {
 		type OriginPrivilegeCmp: PrivilegeCmp<Self::PalletsOrigin>;
 
 		/// The maximum number of scheduled calls in the queue for a single block.
-		/// Not strictly enforced, but used for weight estimation.
 		#[pallet::constant]
 		type MaxScheduledPerBlock: Get<u32>;
 
@@ -243,21 +242,29 @@ pub mod pallet {
 		type WeightInfo: WeightInfo;
 
 		/// The preimage provider with which we look up call hashes to get the call.
-		type PreimageProvider: PreimageProviderAndMaybeRecipient<Self::Hash>;
-
-		/// If `Some` then the number of blocks to postpone execution for when the item is delayed.
-		type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;
+		type Preimages: QueryPreimage + StorePreimage;
 	}
 
-	/// Items to be executed, indexed by the block number that they should be executed on.
 	#[pallet::storage]
-	pub type Agenda<T: Config> =
-		StorageMap<_, Twox64Concat, T::BlockNumber, Vec<Option<ScheduledV3Of<T>>>, ValueQuery>;
+	pub type IncompleteSince<T: Config> = StorageValue<_, T::BlockNumber>;
 
-	/// Lookup from identity to the block number and index of the task.
+	/// Items to be executed, indexed by the block number that they should be executed on.
+	#[pallet::storage]
+	pub type Agenda<T: Config> = StorageMap<
+		_,
+		Twox64Concat,
+		T::BlockNumber,
+		BoundedVec<Option<ScheduledOf<T>>, T::MaxScheduledPerBlock>,
+		ValueQuery,
+	>;
+
+	/// Lookup from a name to the block number and index of the task.
+	///
+	/// For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4
+	/// identities.
 	#[pallet::storage]
 	pub(crate) type Lookup<T: Config> =
-		StorageMap<_, Twox64Concat, Vec<u8>, TaskAddress<T::BlockNumber>>;
+		StorageMap<_, Twox64Concat, TaskName, TaskAddress<T::BlockNumber>>;
 
 	/// Events type.
 	#[pallet::event]
@@ -270,15 +277,15 @@ pub mod pallet {
 		/// Dispatched some task.
 		Dispatched {
 			task: TaskAddress<T::BlockNumber>,
-			id: Option<Vec<u8>>,
+			id: Option<[u8; 32]>,
 			result: DispatchResult,
 		},
 		/// The call for the provided hash was not found so the task has been aborted.
-		CallLookupFailed {
-			task: TaskAddress<T::BlockNumber>,
-			id: Option<Vec<u8>>,
-			error: LookupError,
-		},
+		CallUnavailable { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },
+		/// The given task was unable to be renewed since the agenda is full at that block.
+		PeriodicFailed { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },
+		/// The given task can never be executed since it is overweight.
+		PermanentlyOverweight { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },
 	}
 
 	#[pallet::error]
@@ -291,134 +298,18 @@ pub mod pallet {
 		TargetBlockNumberInPast,
 		/// Reschedule failed because it does not change scheduled time.
 		RescheduleNoChange,
+		/// Attempt to use a non-named function on a named task.
+		Named,
 	}
 
 	#[pallet::hooks]
 	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
 		/// Execute the scheduled calls
 		fn on_initialize(now: T::BlockNumber) -> Weight {
-			let limit = T::MaximumWeight::get();
-
-			let mut queued = Agenda::<T>::take(now)
-				.into_iter()
-				.enumerate()
-				.filter_map(|(index, s)| Some((index as u32, s?)))
-				.collect::<Vec<_>>();
-
-			if queued.len() as u32 > T::MaxScheduledPerBlock::get() {
-				log::warn!(
-					target: "runtime::scheduler",
-					"Warning: This block has more items queued in Scheduler than \
-					expected from the runtime configuration. An update might be needed."
-				);
-			}
-
-			queued.sort_by_key(|(_, s)| s.priority);
-
-			let next = now + One::one();
-
-			let mut total_weight: Weight = T::WeightInfo::on_initialize(0);
-			for (order, (index, mut s)) in queued.into_iter().enumerate() {
-				let named = if let Some(ref id) = s.maybe_id {
-					Lookup::<T>::remove(id);
-					true
-				} else {
-					false
-				};
-
-				let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();
-				s.call = call;
-
-				let resolved = if let Some(completed) = maybe_completed {
-					T::PreimageProvider::unrequest_preimage(&completed);
-					true
-				} else {
-					false
-				};
-
-				let call = match s.call.as_value().cloned() {
-					Some(c) => c,
-					None => {
-						// Preimage not available - postpone until some block.
-						total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));
-						if let Some(delay) = T::NoPreimagePostponement::get() {
-							let until = now.saturating_add(delay);
-							if let Some(ref id) = s.maybe_id {
-								let index = Agenda::<T>::decode_len(until).unwrap_or(0);
-								Lookup::<T>::insert(id, (until, index as u32));
-							}
-							Agenda::<T>::append(until, Some(s));
-						}
-						continue
-					},
-				};
-
-				let periodic = s.maybe_periodic.is_some();
-				let call_weight = call.get_dispatch_info().weight;
-				let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved));
-				let origin = <<T as Config>::RuntimeOrigin as From<T::PalletsOrigin>>::from(
-					s.origin.clone(),
-				)
-				.into();
-				if ensure_signed(origin).is_ok() {
-					// Weights of Signed dispatches expect their signing account to be whitelisted.
-					item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
-				}
-
-				// We allow a scheduled call if any is true:
-				// - It's priority is `HARD_DEADLINE`
-				// - It does not push the weight past the limit.
-				// - It is the first item in the schedule
-				let hard_deadline = s.priority <= schedule::HARD_DEADLINE;
-				let test_weight =
-					total_weight.saturating_add(call_weight).saturating_add(item_weight);
-				if !hard_deadline && order > 0 && test_weight.any_gt(limit) {
-					// Cannot be scheduled this block - postpone until next.
-					total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));
-					if let Some(ref id) = s.maybe_id {
-						// NOTE: We could reasonably not do this (in which case there would be one
-						// block where the named and delayed item could not be referenced by name),
-						// but we will do it anyway since it should be mostly free in terms of
-						// weight and it is slightly cleaner.
-						let index = Agenda::<T>::decode_len(next).unwrap_or(0);
-						Lookup::<T>::insert(id, (next, index as u32));
-					}
-					Agenda::<T>::append(next, Some(s));
-					continue
-				}
-
-				let dispatch_origin = s.origin.clone().into();
-				let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) {
-					Ok(post_info) => (post_info.actual_weight, Ok(())),
-					Err(error_and_info) =>
-						(error_and_info.post_info.actual_weight, Err(error_and_info.error)),
-				};
-				let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight);
-				total_weight.saturating_accrue(item_weight);
-				total_weight.saturating_accrue(actual_call_weight);
-
-				Self::deposit_event(Event::Dispatched {
-					task: (now, index),
-					id: s.maybe_id.clone(),
-					result,
-				});
-
-				if let &Some((period, count)) = &s.maybe_periodic {
-					if count > 1 {
-						s.maybe_periodic = Some((period, count - 1));
-					} else {
-						s.maybe_periodic = None;
-					}
-					let wake = now + period;
-					// If scheduled is named, place its information in `Lookup`
-					if let Some(ref id) = s.maybe_id {
-						let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);
-						Lookup::<T>::insert(id, (wake, wake_index as u32));
-					}
-					Agenda::<T>::append(wake, Some(s));
-				}
-			}
-			total_weight
+			let mut weight_counter =
+				WeightCounter { used: Weight::zero(), limit: T::MaximumWeight::get() };
+			Self::service_agendas(&mut weight_counter, now, u32::max_value());
+			weight_counter.used
 		}
 	}
 
@@ -431,7 +322,7 @@ pub mod pallet {
 			when: T::BlockNumber,
 			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 			priority: schedule::Priority,
-			call: Box<CallOrHashOf<T>>,
+			call: Box<<T as Config>::RuntimeCall>,
 		) -> DispatchResult {
 			T::ScheduleOrigin::ensure_origin(origin.clone())?;
 			let origin = <T as Config>::RuntimeOrigin::from(origin);
@@ -440,7 +331,7 @@ pub mod pallet {
 				maybe_periodic,
 				priority,
 				origin.caller().clone(),
-				*call,
+				T::Preimages::bound(*call)?,
 			)?;
 			Ok(())
 		}
@@ -458,11 +349,11 @@ pub mod pallet {
 		#[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]
 		pub fn schedule_named(
 			origin: OriginFor<T>,
-			id: Vec<u8>,
+			id: TaskName,
 			when: T::BlockNumber,
 			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 			priority: schedule::Priority,
-			call: Box<CallOrHashOf<T>>,
+			call: Box<<T as Config>::RuntimeCall>,
 		) -> DispatchResult {
 			T::ScheduleOrigin::ensure_origin(origin.clone())?;
 			let origin = <T as Config>::RuntimeOrigin::from(origin);
@@ -472,14 +363,14 @@ pub mod pallet {
 				maybe_periodic,
 				priority,
 				origin.caller().clone(),
-				*call,
+				T::Preimages::bound(*call)?,
 			)?;
 			Ok(())
 		}
 
 		/// Cancel a named scheduled task.
 		#[pallet::weight(<T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))]
-		pub fn cancel_named(origin: OriginFor<T>, id: Vec<u8>) -> DispatchResult {
+		pub fn cancel_named(origin: OriginFor<T>, id: TaskName) -> DispatchResult {
 			T::ScheduleOrigin::ensure_origin(origin.clone())?;
 			let origin = <T as Config>::RuntimeOrigin::from(origin);
 			Self::do_cancel_named(Some(origin.caller().clone()), id)?;
@@ -497,7 +388,7 @@ pub mod pallet {
 			after: T::BlockNumber,
 			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 			priority: schedule::Priority,
-			call: Box<CallOrHashOf<T>>,
+			call: Box<<T as Config>::RuntimeCall>,
 		) -> DispatchResult {
 			T::ScheduleOrigin::ensure_origin(origin.clone())?;
 			let origin = <T as Config>::RuntimeOrigin::from(origin);
@@ -506,7 +397,7 @@ pub mod pallet {
 				maybe_periodic,
 				priority,
 				origin.caller().clone(),
-				*call,
+				T::Preimages::bound(*call)?,
 			)?;
 			Ok(())
 		}
@@ -519,11 +410,11 @@ pub mod pallet {
 		#[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]
 		pub fn schedule_named_after(
 			origin: OriginFor<T>,
-			id: Vec<u8>,
+			id: TaskName,
 			after: T::BlockNumber,
 			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 			priority: schedule::Priority,
-			call: Box<CallOrHashOf<T>>,
+			call: Box<<T as Config>::RuntimeCall>,
 		) -> DispatchResult {
 			T::ScheduleOrigin::ensure_origin(origin.clone())?;
 			let origin = <T as Config>::RuntimeOrigin::from(origin);
@@ -533,41 +424,70 @@ pub mod pallet {
 				maybe_periodic,
 				priority,
 				origin.caller().clone(),
-				*call,
+				T::Preimages::bound(*call)?,
 			)?;
 			Ok(())
 		}
 	}
 }
 
-impl<T: Config> Pallet<T> {
-	/// Migrate storage format from V1 to V3.
+impl<T: Config<Hash = PreimageHash>> Pallet<T> {
+	/// Migrate storage format from V1 to V4.
 	///
 	/// Returns the weight consumed by this migration.
-	pub fn migrate_v1_to_v3() -> Weight {
+	pub fn migrate_v1_to_v4() -> Weight {
+		use migration::v1 as old;
 		let mut weight = T::DbWeight::get().reads_writes(1, 1);
 
+		// Delete all undecodable values.
+		// `StorageMap::translate` is not enough since it just skips them and leaves the keys in.
+		let keys = old::Agenda::<T>::iter_keys().collect::<Vec<_>>();
+		for key in keys {
+			weight.saturating_accrue(T::DbWeight::get().reads(1));
+			if let Err(_) = old::Agenda::<T>::try_get(&key) {
+				weight.saturating_accrue(T::DbWeight::get().writes(1));
+				old::Agenda::<T>::remove(&key);
+				log::warn!("Deleted undecodable agenda");
+			}
+		}
+
 		Agenda::<T>::translate::<
 			Vec<Option<ScheduledV1<<T as Config>::RuntimeCall, T::BlockNumber>>>,
 			_,
 		>(|_, agenda| {
-			Some(
+			Some(BoundedVec::truncate_from(
 				agenda
 					.into_iter()
 					.map(|schedule| {
 						weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
 
-						schedule.map(|schedule| ScheduledV3 {
-							maybe_id: schedule.maybe_id,
-							priority: schedule.priority,
-							call: schedule.call.into(),
-							maybe_periodic: schedule.maybe_periodic,
-							origin: system::RawOrigin::Root.into(),
-							_phantom: Default::default(),
+						schedule.and_then(|schedule| {
+							if let Some(id) = schedule.maybe_id.as_ref() {
+								let name = blake2_256(id);
+								if let Some(item) = old::Lookup::<T>::take(id) {
+									Lookup::<T>::insert(name, item);
+								}
+								weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
+							}
+
+							let call = T::Preimages::bound(schedule.call).ok()?;
+
+							if call.lookup_needed() {
+								weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1));
+							}
+
+							Some(Scheduled {
+								maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])),
+								priority: schedule.priority,
+								call,
+								maybe_periodic: schedule.maybe_periodic,
+								origin: system::RawOrigin::Root.into(),
+								_phantom: Default::default(),
+							})
 						})
 					})
 					.collect::<Vec<_>>(),
-			)
+			))
 		});
 
 		#[allow(deprecated)]
@@ -577,34 +497,62 @@ impl<T: Config> Pallet<T> {
 			&[],
 		);
 
-		StorageVersion::new(3).put::<Self>();
+		StorageVersion::new(4).put::<Self>();
 
 		weight + T::DbWeight::get().writes(2)
 	}
 
-	/// Migrate storage format from V2 to V3.
+	/// Migrate storage format from V2 to V4.
 	///
 	/// Returns the weight consumed by this migration.
-	pub fn migrate_v2_to_v3() -> Weight {
+	pub fn migrate_v2_to_v4() -> Weight {
+		use migration::v2 as old;
 		let mut weight = T::DbWeight::get().reads_writes(1, 1);
 
+		// Delete all undecodable values.
+		// `StorageMap::translate` is not enough since it just skips them and leaves the keys in.
+		let keys = old::Agenda::<T>::iter_keys().collect::<Vec<_>>();
+		for key in keys {
+			weight.saturating_accrue(T::DbWeight::get().reads(1));
+			if let Err(_) = old::Agenda::<T>::try_get(&key) {
+				weight.saturating_accrue(T::DbWeight::get().writes(1));
+				old::Agenda::<T>::remove(&key);
+				log::warn!("Deleted undecodable agenda");
+			}
+		}
+
 		Agenda::<T>::translate::<Vec<Option<ScheduledV2Of<T>>>, _>(|_, agenda| {
-			Some(
+			Some(BoundedVec::truncate_from(
 				agenda
 					.into_iter()
 					.map(|schedule| {
 						weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
-						schedule.map(|schedule| ScheduledV3 {
-							maybe_id: schedule.maybe_id,
-							priority: schedule.priority,
-							call: schedule.call.into(),
-							maybe_periodic: schedule.maybe_periodic,
-							origin: schedule.origin,
-							_phantom: Default::default(),
+						schedule.and_then(|schedule| {
+							if let Some(id) = schedule.maybe_id.as_ref() {
+								let name = blake2_256(id);
+								if let Some(item) = old::Lookup::<T>::take(id) {
+									Lookup::<T>::insert(name, item);
+								}
+								weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
+							}
+
+							let call = T::Preimages::bound(schedule.call).ok()?;
+							if call.lookup_needed() {
+								weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1));
+							}
+
+							Some(Scheduled {
+								maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])),
+								priority: schedule.priority,
+								call,
+								maybe_periodic: schedule.maybe_periodic,
+								origin: schedule.origin,
+								_phantom: Default::default(),
+							})
 						})
 					})
 					.collect::<Vec<_>>(),
-			)
+			))
 		});
 
 		#[allow(deprecated)]
@@ -614,34 +562,140 @@ impl<T: Config> Pallet<T> {
 			&[],
 		);
 
-		StorageVersion::new(3).put::<Self>();
+		StorageVersion::new(4).put::<Self>();
 
 		weight + T::DbWeight::get().writes(2)
 	}
 
-	#[cfg(feature = "try-runtime")]
-	pub fn pre_migrate_to_v3() -> Result<(), &'static str> {
-		Ok(())
-	}
+	/// Migrate storage format from V3 to V4.
+	///
+	/// Returns the weight consumed by this migration.
+	#[allow(deprecated)]
+	pub fn migrate_v3_to_v4() -> Weight {
+		use migration::v3 as old;
+		let mut weight = T::DbWeight::get().reads_writes(2, 1);
+
+		// Delete all undecodable values.
+		// `StorageMap::translate` is not enough since it just skips them and leaves the keys in.
+		let blocks = old::Agenda::<T>::iter_keys().collect::<Vec<_>>();
+		for block in blocks {
+			weight.saturating_accrue(T::DbWeight::get().reads(1));
+			if let Err(_) = old::Agenda::<T>::try_get(&block) {
+				weight.saturating_accrue(T::DbWeight::get().writes(1));
+				old::Agenda::<T>::remove(&block);
+				log::warn!("Deleted undecodable agenda of block: {:?}", block);
+			}
+		}
 
-	#[cfg(feature = "try-runtime")]
-	pub fn post_migrate_to_v3() -> Result<(), &'static str> {
-		use frame_support::dispatch::GetStorageVersion;
+		Agenda::<T>::translate::<Vec<Option<ScheduledV3Of<T>>>, _>(|block, agenda| {
+			log::info!("Migrating agenda of block: {:?}", &block);
+			Some(BoundedVec::truncate_from(
+				agenda
+					.into_iter()
+					.map(|schedule| {
+						weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
+						schedule
+							.and_then(|schedule| {
+								if let Some(id) = schedule.maybe_id.as_ref() {
+									let name = blake2_256(id);
+									if let Some(item) = old::Lookup::<T>::take(id) {
+										Lookup::<T>::insert(name, item);
+										log::info!("Migrated name for id: {:?}", id);
+									} else {
+										log::error!("No name in Lookup for id: {:?}", &id);
+									}
+									weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
+								} else {
+									log::info!("Schedule is unnamed");
+								}
+
+								let call = match schedule.call {
+									MaybeHashed::Hash(h) => {
+										let bounded = Bounded::from_legacy_hash(h);
+										// Check that the call can be decoded in the new runtime.
+										if let Err(err) = T::Preimages::peek::<
+											<T as Config>::RuntimeCall,
+										>(&bounded)
+										{
+											log::error!(
+												"Dropping undecodable call {}: {:?}",
+												&h,
+												&err
+											);
+											return None
+										}
+										weight.saturating_accrue(T::DbWeight::get().reads(1));
+										log::info!("Migrated call by hash, hash: {:?}", h);
+										bounded
+									},
+									MaybeHashed::Value(v) => {
+										let call = T::Preimages::bound(v)
+											.map_err(|e| {
+												log::error!("Could not bound Call: {:?}", e)
+											})
+											.ok()?;
+										if call.lookup_needed() {
+											weight.saturating_accrue(
+												T::DbWeight::get().reads_writes(0, 1),
+											);
+										}
+										log::info!(
+											"Migrated call by value, hash: {:?}",
+											call.hash()
+										);
+										call
+									},
+								};
+
+								Some(Scheduled {
+									maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])),
+									priority: schedule.priority,
+									call,
+									maybe_periodic: schedule.maybe_periodic,
+									origin: schedule.origin,
+									_phantom: Default::default(),
+								})
+							})
+							.or_else(|| {
+								log::info!("Schedule in agenda for block {:?} is empty - nothing to do here.", &block);
+								None
+							})
+					})
+					.collect::<Vec<_>>(),
+			))
+		});
 
-		assert!(Self::current_storage_version() == 3);
-		for k in Agenda::<T>::iter_keys() {
-			let _ = Agenda::<T>::try_get(k).map_err(|()| "Invalid item in Agenda")?;
-		}
-		Ok(())
+		#[allow(deprecated)]
+		frame_support::storage::migration::remove_storage_prefix(
+			Self::name().as_bytes(),
+			b"StorageVersion",
+			&[],
+		);
+
+		StorageVersion::new(4).put::<Self>();
+
+		weight + T::DbWeight::get().writes(2)
 	}
+}
 
+impl<T: Config> Pallet<T> {
 	/// Helper to migrate scheduler when the pallet origin type has changed.
 	pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {
 		Agenda::<T>::translate::<
-			Vec<Option<Scheduled<CallOrHashOf<T>, T::BlockNumber, OldOrigin, T::AccountId>>>,
+			Vec<
+				Option<
+					Scheduled<
+						TaskName,
+						Bounded<<T as Config>::RuntimeCall>,
+						T::BlockNumber,
+						OldOrigin,
+						T::AccountId,
+					>,
+				>,
+			>,
 			_,
 		>(|_, agenda| {
-			Some(
+			Some(BoundedVec::truncate_from(
 				agenda
 					.into_iter()
 					.map(|schedule| {
@@ -655,7 +709,7 @@ impl<T: Config> Pallet<T> {
 						})
 					})
 					.collect::<Vec<_>>(),
-			)
+			))
 		});
 	}
 
@@ -676,34 +730,64 @@ impl<T: Config> Pallet<T> {
 		Ok(when)
 	}
 
+	fn place_task(
+		when: T::BlockNumber,
+		what: ScheduledOf<T>,
+	) -> Result<TaskAddress<T::BlockNumber>, (DispatchError, ScheduledOf<T>)> {
+		let maybe_name = what.maybe_id;
+		let index = Self::push_to_agenda(when, what)?;
+		let address = (when, index);
+		if let Some(name) = maybe_name {
+			Lookup::<T>::insert(name, address)
+		}
+		Self::deposit_event(Event::Scheduled { when: address.0, index: address.1 });
+		Ok(address)
+	}
+
+	fn push_to_agenda(
+		when: T::BlockNumber,
+		what: ScheduledOf<T>,
+	) -> Result<u32, (DispatchError, ScheduledOf<T>)> {
+		let mut agenda = Agenda::<T>::get(when);
+		let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() {
+			// will always succeed due to the above check.
+			let _ = agenda.try_push(Some(what));
+			agenda.len() as u32 - 1
+		} else {
+			if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) {
+				agenda[hole_index] = Some(what);
+				hole_index as u32
+			} else {
+				return Err((DispatchError::Exhausted, what))
+			}
+		};
+		Agenda::<T>::insert(when, agenda);
+		Ok(index)
+	}
+
 	fn do_schedule(
 		when: DispatchTime<T::BlockNumber>,
 		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 		priority: schedule::Priority,
 		origin: T::PalletsOrigin,
-		call: CallOrHashOf<T>,
+		call: Bounded<<T as Config>::RuntimeCall>,
 	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
 		let when = Self::resolve_time(when)?;
-		call.ensure_requested::<T::PreimageProvider>();
 
 		// sanitize maybe_periodic
 		let maybe_periodic = maybe_periodic
 			.filter(|p| p.1 > 1 && !p.0.is_zero())
 			// Remove one from the number of repetitions since we will schedule one now.
 			.map(|(p, c)| (p, c - 1));
-		let s = Some(Scheduled {
+		let task = Scheduled {
 			maybe_id: None,
 			priority,
 			call,
 			maybe_periodic,
 			origin,
-			_phantom: PhantomData::<T::AccountId>::default(),
-		});
-		Agenda::<T>::append(when, s);
-		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;
-		Self::deposit_event(Event::Scheduled { when, index });
-
-		Ok((when, index))
+			_phantom: PhantomData,
+		};
+		Self::place_task(when, task).map_err(|x| x.0)
 	}
 
 	fn do_cancel(
@@ -713,7 +797,7 @@ impl<T: Config> Pallet<T> {
 		let scheduled = Agenda::<T>::try_mutate(when, |agenda| {
 			agenda.get_mut(index as usize).map_or(
 				Ok(None),
-				|s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {
+				|s| -> Result<Option<Scheduled<_, _, _, _, _>>, DispatchError> {
 					if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {
 						if matches!(
 							T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),
@@ -727,7 +811,7 @@ impl<T: Config> Pallet<T> {
 			)
 		})?;
 		if let Some(s) = scheduled {
-			s.call.ensure_unrequested::<T::PreimageProvider>();
+			T::Preimages::drop(&s.call);
 			if let Some(id) = s.maybe_id {
 				Lookup::<T>::remove(id);
 			}
@@ -748,27 +832,23 @@ impl<T: Config> Pallet<T> {
 			return Err(Error::<T>::RescheduleNoChange.into())
 		}
 
-		Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {
+		let task = Agenda::<T>::try_mutate(when, |agenda| {
 			let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;
-			let task = task.take().ok_or(Error::<T>::NotFound)?;
-			Agenda::<T>::append(new_time, Some(task));
-			Ok(())
+			ensure!(!matches!(task, Some(Scheduled { maybe_id: Some(_), .. })), Error::<T>::Named);
+			task.take().ok_or(Error::<T>::NotFound)
 		})?;
-
-		let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
 		Self::deposit_event(Event::Canceled { when, index });
-		Self::deposit_event(Event::Scheduled { when: new_time, index: new_index });
 
-		Ok((new_time, new_index))
+		Self::place_task(new_time, task).map_err(|x| x.0)
 	}
 
 	fn do_schedule_named(
-		id: Vec<u8>,
+		id: TaskName,
 		when: DispatchTime<T::BlockNumber>,
 		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
 		priority: schedule::Priority,
 		origin: T::PalletsOrigin,
-		call: CallOrHashOf<T>,
+		call: Bounded<<T as Config>::RuntimeCall>,
 	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
 		// ensure id it is unique
 		if Lookup::<T>::contains_key(&id) {
@@ -777,32 +857,24 @@ impl<T: Config> Pallet<T> {
 
 		let when = Self::resolve_time(when)?;
 
-		call.ensure_requested::<T::PreimageProvider>();
-
 		// sanitize maybe_periodic
 		let maybe_periodic = maybe_periodic
 			.filter(|p| p.1 > 1 && !p.0.is_zero())
 			// Remove one from the number of repetitions since we will schedule one now.
 			.map(|(p, c)| (p, c - 1));
 
-		let s = Scheduled {
-			maybe_id: Some(id.clone()),
+		let task = Scheduled {
+			maybe_id: Some(id),
 			priority,
 			call,
 			maybe_periodic,
 			origin,
 			_phantom: Default::default(),
 		};
-		Agenda::<T>::append(when, Some(s));
-		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;
-		let address = (when, index);
-		Lookup::<T>::insert(&id, &address);
-		Self::deposit_event(Event::Scheduled { when, index });
-
-		Ok(address)
+		Self::place_task(when, task).map_err(|x| x.0)
 	}
 
-	fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: Vec<u8>) -> DispatchResult {
+	fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: TaskName) -> DispatchResult {
 		Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {
 			if let Some((when, index)) = lookup.take() {
 				let i = index as usize;
@@ -815,7 +887,7 @@ impl<T: Config> Pallet<T> {
 							) {
 								return Err(BadOrigin.into())
 							}
-							s.call.ensure_unrequested::<T::PreimageProvider>();
+							T::Preimages::drop(&s.call);
 						}
 						*s = None;
 					}
@@ -830,42 +902,245 @@ impl<T: Config> Pallet<T> {
 	}
 
 	fn do_reschedule_named(
-		id: Vec<u8>,
+		id: TaskName,
 		new_time: DispatchTime<T::BlockNumber>,
 	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
 		let new_time = Self::resolve_time(new_time)?;
 
-		Lookup::<T>::try_mutate_exists(
-			id,
-			|lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
-				let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;
+		let lookup = Lookup::<T>::get(id);
+		let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;
 
-				if new_time == when {
-					return Err(Error::<T>::RescheduleNoChange.into())
-				}
+		if new_time == when {
+			return Err(Error::<T>::RescheduleNoChange.into())
+		}
 
-				Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {
-					let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;
-					let task = task.take().ok_or(Error::<T>::NotFound)?;
-					Agenda::<T>::append(new_time, Some(task));
+		let task = Agenda::<T>::try_mutate(when, |agenda| {
+			let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;
+			task.take().ok_or(Error::<T>::NotFound)
+		})?;
+		Self::deposit_event(Event::Canceled { when, index });
+		Self::place_task(new_time, task).map_err(|x| x.0)
+	}
+}
 
-					Ok(())
-				})?;
+enum ServiceTaskError {
+	/// Could not be executed due to missing preimage.
+	Unavailable,
+	/// Could not be executed due to weight limitations.
+	Overweight,
+}
+use ServiceTaskError::*;
 
-				let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
-				Self::deposit_event(Event::Canceled { when, index });
-				Self::deposit_event(Event::Scheduled { when: new_time, index: new_index });
+impl<T: Config> Pallet<T> {
+	/// Service up to `max` agendas queue starting from earliest incompletely executed agenda.
+	fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) {
+		if !weight.check_accrue(T::WeightInfo::service_agendas_base()) {
+			return
+		}
+
+		let mut incomplete_since = now + One::one();
+		let mut when = IncompleteSince::<T>::take().unwrap_or(now);
+		let mut executed = 0;
+
+		let max_items = T::MaxScheduledPerBlock::get();
+		let mut count_down = max;
+		let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items);
+		while count_down > 0 && when <= now && weight.can_accrue(service_agenda_base_weight) {
+			if !Self::service_agenda(weight, &mut executed, now, when, u32::max_value()) {
+				incomplete_since = incomplete_since.min(when);
+			}
+			when.saturating_inc();
+			count_down.saturating_dec();
+		}
+		incomplete_since = incomplete_since.min(when);
+		if incomplete_since <= now {
+			IncompleteSince::<T>::put(incomplete_since);
+		}
+	}
+
+	/// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a
+	/// later block.
+	fn service_agenda(
+		weight: &mut WeightCounter,
+		executed: &mut u32,
+		now: T::BlockNumber,
+		when: T::BlockNumber,
+		max: u32,
+	) -> bool {
+		let mut agenda = Agenda::<T>::get(when);
+		let mut ordered = agenda
+			.iter()
+			.enumerate()
+			.filter_map(|(index, maybe_item)| {
+				maybe_item.as_ref().map(|item| (index as u32, item.priority))
+			})
+			.collect::<Vec<_>>();
+		ordered.sort_by_key(|k| k.1);
+		let within_limit =
+			weight.check_accrue(T::WeightInfo::service_agenda_base(ordered.len() as u32));
+		debug_assert!(within_limit, "weight limit should have been checked in advance");
+
+		// Items which we know can be executed and have postponed for execution in a later block.
+		let mut postponed = (ordered.len() as u32).saturating_sub(max);
+		// Items which we don't know can ever be executed.
+		let mut dropped = 0;
+
+		for (agenda_index, _) in ordered.into_iter().take(max as usize) {
+			let task = match agenda[agenda_index as usize].take() {
+				None => continue,
+				Some(t) => t,
+			};
+			let base_weight = T::WeightInfo::service_task(
+				task.call.lookup_len().map(|x| x as usize),
+				task.maybe_id.is_some(),
+				task.maybe_periodic.is_some(),
+			);
+			if !weight.can_accrue(base_weight) {
+				postponed += 1;
+				break
+			}
+			let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task);
+			agenda[agenda_index as usize] = match result {
+				Err((Unavailable, slot)) => {
+					dropped += 1;
+					slot
+				},
+				Err((Overweight, slot)) => {
+					postponed += 1;
+					slot
+				},
+				Ok(()) => {
+					*executed += 1;
+					None
+				},
+			};
+		}
+		if postponed > 0 || dropped > 0 {
+			Agenda::<T>::insert(when, agenda);
+		} else {
+			Agenda::<T>::remove(when);
+		}
+		postponed == 0
+	}
 
-				*lookup = Some((new_time, new_index));
+	/// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter.
+	///
+	/// This involves:
+	/// - removing and potentially replacing the `Lookup` entry for the task.
+	/// - realizing the task's call which can include a preimage lookup.
+	/// - Rescheduling the task for execution in a later agenda if periodic.
+	fn service_task(
+		weight: &mut WeightCounter,
+		now: T::BlockNumber,
+		when: T::BlockNumber,
+		agenda_index: u32,
+		is_first: bool,
+		mut task: ScheduledOf<T>,
+	) -> Result<(), (ServiceTaskError, Option<ScheduledOf<T>>)> {
+		if let Some(ref id) = task.maybe_id {
+			Lookup::<T>::remove(id);
+		}
 
-				Ok((new_time, new_index))
+		let (call, lookup_len) = match T::Preimages::peek(&task.call) {
+			Ok(c) => c,
+			Err(_) => return Err((Unavailable, Some(task))),
+		};
+
+		weight.check_accrue(T::WeightInfo::service_task(
+			lookup_len.map(|x| x as usize),
+			task.maybe_id.is_some(),
+			task.maybe_periodic.is_some(),
+		));
+
+		match Self::execute_dispatch(weight, task.origin.clone(), call) {
+			Err(Unavailable) => {
+				debug_assert!(false, "Checked to exist with `peek`");
+				Self::deposit_event(Event::CallUnavailable {
+					task: (when, agenda_index),
+					id: task.maybe_id,
+				});
+				Err((Unavailable, Some(task)))
+			},
+			Err(Overweight) if is_first => {
+				T::Preimages::drop(&task.call);
+				Self::deposit_event(Event::PermanentlyOverweight {
+					task: (when, agenda_index),
+					id: task.maybe_id,
+				});
+				Err((Unavailable, Some(task)))
+			},
+			Err(Overweight) => Err((Overweight, Some(task))),
+			Ok(result) => {
+				Self::deposit_event(Event::Dispatched {
+					task: (when, agenda_index),
+					id: task.maybe_id,
+					result,
+				});
+				if let &Some((period, count)) = &task.maybe_periodic {
+					if count > 1 {
+						task.maybe_periodic = Some((period, count - 1));
+					} else {
+						task.maybe_periodic = None;
+					}
+					let wake = now.saturating_add(period);
+					match Self::place_task(wake, task) {
+						Ok(_) => {},
+						Err((_, task)) => {
+							// TODO: Leave task in storage somewhere for it to be rescheduled
+							// manually.
+							T::Preimages::drop(&task.call);
+							Self::deposit_event(Event::PeriodicFailed {
+								task: (when, agenda_index),
+								id: task.maybe_id,
+							});
+						},
+					}
+				} else {
+					T::Preimages::drop(&task.call);
+				}
+				Ok(())
 			},
-		)
+		}
+	}
+
+	/// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight`
+	/// counter does not exceed its limit and that it is counted accurately (e.g. accounted using
+	/// post info if available).
+	///
+	/// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the
+	/// call itself).
+	fn execute_dispatch(
+		weight: &mut WeightCounter,
+		origin: T::PalletsOrigin,
+		call: <T as Config>::RuntimeCall,
+	) -> Result<DispatchResult, ServiceTaskError> {
+		let base_weight = match origin.as_system_ref() {
+			Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(),
+			_ => T::WeightInfo::execute_dispatch_unsigned(),
+		};
+		let call_weight = call.get_dispatch_info().weight;
+		// We only allow a scheduled call if it cannot push the weight past the limit.
+		let max_weight = base_weight.saturating_add(call_weight);
+
+		if !weight.can_accrue(max_weight) {
+			return Err(Overweight)
+		}
+
+		let dispatch_origin = origin.into();
+		let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) {
+			Ok(post_info) => (post_info.actual_weight, Ok(())),
+			Err(error_and_info) =>
+				(error_and_info.post_info.actual_weight, Err(error_and_info.error)),
+		};
+		let call_weight = maybe_actual_call_weight.unwrap_or(call_weight);
+		weight.check_accrue(base_weight);
+		weight.check_accrue(call_weight);
+		Ok(result)
 	}
 }
 
-impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin>
-	for Pallet<T>
+impl<T: Config<Hash = PreimageHash>>
+	schedule::v2::Anon<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin> for Pallet<T>
 {
 	type Address = TaskAddress<T::BlockNumber>;
 	type Hash = T::Hash;
@@ -877,6 +1152,8 @@ impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::RuntimeCall, T
 		origin: T::PalletsOrigin,
 		call: CallOrHashOf<T>,
 	) -> Result<Self::Address, DispatchError> {
+		let call = call.as_value().ok_or(DispatchError::CannotLookup)?;
+		let call = T::Preimages::bound(call)?.transmute();
 		Self::do_schedule(when, maybe_periodic, priority, origin, call)
 	}
 
@@ -896,8 +1173,8 @@ impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::RuntimeCall, T
 	}
 }
 
-impl<T: Config> schedule::v2::Named<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin>
-	for Pallet<T>
+impl<T: Config<Hash = PreimageHash>>
+	schedule::v2::Named<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin> for Pallet<T>
 {
 	type Address = TaskAddress<T::BlockNumber>;
 	type Hash = T::Hash;
@@ -910,23 +1187,108 @@ impl<T: Config> schedule::v2::Named<T::BlockNumber, <T as Config>::RuntimeCall,
 		origin: T::PalletsOrigin,
 		call: CallOrHashOf<T>,
 	) -> Result<Self::Address, ()> {
-		Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ())
+		let call = call.as_value().ok_or(())?;
+		let call = T::Preimages::bound(call).map_err(|_| ())?.transmute();
+		let name = blake2_256(&id[..]);
+		Self::do_schedule_named(name, when, maybe_periodic, priority, origin, call).map_err(|_| ())
 	}
 
 	fn cancel_named(id: Vec<u8>) -> Result<(), ()> {
-		Self::do_cancel_named(None, id).map_err(|_| ())
+		let name = blake2_256(&id[..]);
+		Self::do_cancel_named(None, name).map_err(|_| ())
 	}
 
 	fn reschedule_named(
 		id: Vec<u8>,
 		when: DispatchTime<T::BlockNumber>,
 	) -> Result<Self::Address, DispatchError> {
-		Self::do_reschedule_named(id, when)
+		let name = blake2_256(&id[..]);
+		Self::do_reschedule_named(name, when)
 	}
 
 	fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {
-		Lookup::<T>::get(id)
+		let name = blake2_256(&id[..]);
+		Lookup::<T>::get(name)
 			.and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))
 			.ok_or(())
 	}
 }
+
+impl<T: Config> schedule::v3::Anon<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin>
+	for Pallet<T>
+{
+	type Address = TaskAddress<T::BlockNumber>;
+
+	fn schedule(
+		when: DispatchTime<T::BlockNumber>,
+		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+		priority: schedule::Priority,
+		origin: T::PalletsOrigin,
+		call: Bounded<<T as Config>::RuntimeCall>,
+	) -> Result<Self::Address, DispatchError> {
+		Self::do_schedule(when, maybe_periodic, priority, origin, call)
+	}
+
+	fn cancel((when, index): Self::Address) -> Result<(), DispatchError> {
+		Self::do_cancel(None, (when, index)).map_err(map_err_to_v3_err::<T>)
+	}
+
+	fn reschedule(
+		address: Self::Address,
+		when: DispatchTime<T::BlockNumber>,
+	) -> Result<Self::Address, DispatchError> {
+		Self::do_reschedule(address, when).map_err(map_err_to_v3_err::<T>)
+	}
+
+	fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, DispatchError> {
+		Agenda::<T>::get(when)
+			.get(index as usize)
+			.ok_or(DispatchError::Unavailable)
+			.map(|_| when)
+	}
+}
+
+use schedule::v3::TaskName;
+
+impl<T: Config> schedule::v3::Named<T::BlockNumber, <T as Config>::RuntimeCall, T::PalletsOrigin>
+	for Pallet<T>
+{
+	type Address = TaskAddress<T::BlockNumber>;
+
+	fn schedule_named(
+		id: TaskName,
+		when: DispatchTime<T::BlockNumber>,
+		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+		priority: schedule::Priority,
+		origin: T::PalletsOrigin,
+		call: Bounded<<T as Config>::RuntimeCall>,
+	) -> Result<Self::Address, DispatchError> {
+		Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call)
+	}
+
+	fn cancel_named(id: TaskName) -> Result<(), DispatchError> {
+		Self::do_cancel_named(None, id).map_err(map_err_to_v3_err::<T>)
+	}
+
+	fn reschedule_named(
+		id: TaskName,
+		when: DispatchTime<T::BlockNumber>,
+	) -> Result<Self::Address, DispatchError> {
+		Self::do_reschedule_named(id, when).map_err(map_err_to_v3_err::<T>)
+	}
+
+	fn next_dispatch_time(id: TaskName) -> Result<T::BlockNumber, DispatchError> {
+		Lookup::<T>::get(id)
+			.and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))
+			.ok_or(DispatchError::Unavailable)
+	}
+}
+
+/// Maps a pallet error to an `schedule::v3` error.
+fn map_err_to_v3_err<T: Config>(err: DispatchError) -> DispatchError {
+	if err == DispatchError::from(Error::<T>::NotFound) {
+		DispatchError::Unavailable
+	} else {
+		err
+	}
+}
diff --git a/substrate/frame/scheduler/src/migration.rs b/substrate/frame/scheduler/src/migration.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6769d20023196d1d8eb9b2d001bb43843b0ca9f7
--- /dev/null
+++ b/substrate/frame/scheduler/src/migration.rs
@@ -0,0 +1,402 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Migrations for the scheduler pallet.
+
+use super::*;
+use frame_support::traits::OnRuntimeUpgrade;
+
+/// The log target.
+const TARGET: &'static str = "runtime::scheduler::migration";
+
+pub mod v1 {
+	use super::*;
+	use frame_support::pallet_prelude::*;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Agenda<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		<T as frame_system::Config>::BlockNumber,
+		Vec<
+			Option<
+				ScheduledV1<<T as Config>::RuntimeCall, <T as frame_system::Config>::BlockNumber>,
+			>,
+		>,
+		ValueQuery,
+	>;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Lookup<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		Vec<u8>,
+		TaskAddress<<T as frame_system::Config>::BlockNumber>,
+	>;
+}
+
+pub mod v2 {
+	use super::*;
+	use frame_support::pallet_prelude::*;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Agenda<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		<T as frame_system::Config>::BlockNumber,
+		Vec<Option<ScheduledV2Of<T>>>,
+		ValueQuery,
+	>;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Lookup<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		Vec<u8>,
+		TaskAddress<<T as frame_system::Config>::BlockNumber>,
+	>;
+}
+
+pub mod v3 {
+	use super::*;
+	use frame_support::pallet_prelude::*;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Agenda<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		<T as frame_system::Config>::BlockNumber,
+		Vec<Option<ScheduledV3Of<T>>>,
+		ValueQuery,
+	>;
+
+	#[frame_support::storage_alias]
+	pub(crate) type Lookup<T: Config> = StorageMap<
+		Pallet<T>,
+		Twox64Concat,
+		Vec<u8>,
+		TaskAddress<<T as frame_system::Config>::BlockNumber>,
+	>;
+
+	/// Migrate the scheduler pallet from V3 to V4.
+	pub struct MigrateToV4<T>(sp_std::marker::PhantomData<T>);
+
+	impl<T: Config<Hash = PreimageHash>> OnRuntimeUpgrade for MigrateToV4<T> {
+		#[cfg(feature = "try-runtime")]
+		fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 3, "Can only upgrade from version 3");
+
+			let agendas = Agenda::<T>::iter_keys().count() as u32;
+			let decodable_agendas = Agenda::<T>::iter_values().count() as u32;
+			if agendas != decodable_agendas {
+				// This is not necessarily an error, but can happen when there are Calls
+				// in an Agenda that are not valid anymore with the new runtime.
+				log::error!(
+					target: TARGET,
+					"Can only decode {} of {} agendas - others will be dropped",
+					decodable_agendas,
+					agendas
+				);
+			}
+			log::info!(target: TARGET, "Trying to migrate {} agendas...", decodable_agendas);
+
+			// Check that no agenda overflows `MaxScheduledPerBlock`.
+			let max_scheduled_per_block = T::MaxScheduledPerBlock::get() as usize;
+			for (block_number, agenda) in Agenda::<T>::iter() {
+				if agenda.iter().cloned().filter_map(|s| s).count() > max_scheduled_per_block {
+					log::error!(
+						target: TARGET,
+						"Would truncate agenda of block {:?} from {} items to {} items.",
+						block_number,
+						agenda.len(),
+						max_scheduled_per_block,
+					);
+					return Err("Agenda would overflow `MaxScheduledPerBlock`.")
+				}
+			}
+			// Check that bounding the calls will not overflow `MAX_LENGTH`.
+			let max_length = T::Preimages::MAX_LENGTH as usize;
+			for (block_number, agenda) in Agenda::<T>::iter() {
+				for schedule in agenda.iter().cloned().filter_map(|s| s) {
+					match schedule.call {
+						frame_support::traits::schedule::MaybeHashed::Value(call) => {
+							let l = call.using_encoded(|c| c.len());
+							if l > max_length {
+								log::error!(
+									target: TARGET,
+									"Call in agenda of block {:?} is too large: {} byte",
+									block_number,
+									l,
+								);
+								return Err("Call is too large.")
+							}
+						},
+						_ => (),
+					}
+				}
+			}
+
+			Ok((decodable_agendas as u32).encode())
+		}
+
+		fn on_runtime_upgrade() -> Weight {
+			let version = StorageVersion::get::<Pallet<T>>();
+			if version != 3 {
+				log::warn!(
+					target: TARGET,
+					"skipping v3 to v4 migration: executed on wrong storage version.\
+				Expected version 3, found {:?}",
+					version,
+				);
+				return T::DbWeight::get().reads(1)
+			}
+
+			crate::Pallet::<T>::migrate_v3_to_v4()
+		}
+
+		#[cfg(feature = "try-runtime")]
+		fn post_upgrade(state: Vec<u8>) -> Result<(), &'static str> {
+			assert_eq!(StorageVersion::get::<Pallet<T>>(), 4, "Must upgrade");
+
+			// Check that everything decoded fine.
+			for k in crate::Agenda::<T>::iter_keys() {
+				assert!(crate::Agenda::<T>::try_get(k).is_ok(), "Cannot decode V4 Agenda");
+			}
+
+			let old_agendas: u32 =
+				Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed");
+			let new_agendas = crate::Agenda::<T>::iter_keys().count() as u32;
+			if old_agendas != new_agendas {
+				// This is not necessarily an error, but can happen when there are Calls
+				// in an Agenda that are not valid anymore in the new runtime.
+				log::error!(
+					target: TARGET,
+					"Did not migrate all Agendas. Previous {}, Now {}",
+					old_agendas,
+					new_agendas,
+				);
+			} else {
+				log::info!(target: TARGET, "Migrated {} agendas.", new_agendas);
+			}
+
+			Ok(())
+		}
+	}
+}
+
+#[cfg(test)]
+#[cfg(feature = "try-runtime")]
+mod test {
+	use super::*;
+	use crate::mock::*;
+	use frame_support::Hashable;
+	use sp_std::borrow::Cow;
+	use substrate_test_utils::assert_eq_uvec;
+
+	#[test]
+	#[allow(deprecated)]
+	fn migration_v3_to_v4_works() {
+		new_test_ext().execute_with(|| {
+			// Assume that we are at V3.
+			StorageVersion::new(3).put::<Scheduler>();
+
+			// Call that will be bounded to a `Lookup`.
+			let large_call =
+				RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1024] });
+			// Call that can be inlined.
+			let small_call =
+				RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 10] });
+			// Call that is already hashed and can will be converted to `Legacy`.
+			let hashed_call =
+				RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 2048] });
+			let bound_hashed_call = Preimage::bound(hashed_call.clone()).unwrap();
+			assert!(bound_hashed_call.lookup_needed());
+			// A Call by hash that will fail to decode becomes `None`.
+			let trash_data = vec![255u8; 1024];
+			let undecodable_hash = Preimage::note(Cow::Borrowed(&trash_data)).unwrap();
+
+			for i in 0..2u64 {
+				let k = i.twox_64_concat();
+				let old = vec![
+					Some(ScheduledV3Of::<Test> {
+						maybe_id: None,
+						priority: i as u8 + 10,
+						call: small_call.clone().into(),
+						maybe_periodic: None, // 1
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					None,
+					Some(ScheduledV3Of::<Test> {
+						maybe_id: Some(vec![i as u8; 32]),
+						priority: 123,
+						call: large_call.clone().into(),
+						maybe_periodic: Some((4u64, 20)),
+						origin: signed(i),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					Some(ScheduledV3Of::<Test> {
+						maybe_id: Some(vec![255 - i as u8; 320]),
+						priority: 123,
+						call: MaybeHashed::Hash(bound_hashed_call.hash()),
+						maybe_periodic: Some((8u64, 10)),
+						origin: signed(i),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					Some(ScheduledV3Of::<Test> {
+						maybe_id: Some(vec![i as u8; 320]),
+						priority: 123,
+						call: MaybeHashed::Hash(undecodable_hash.clone()),
+						maybe_periodic: Some((4u64, 20)),
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+				];
+				frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);
+			}
+
+			let state = v3::MigrateToV4::<Test>::pre_upgrade().unwrap();
+			let _w = v3::MigrateToV4::<Test>::on_runtime_upgrade();
+			v3::MigrateToV4::<Test>::post_upgrade(state).unwrap();
+
+			let mut x = Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>();
+			x.sort_by_key(|x| x.0);
+
+			let bound_large_call = Preimage::bound(large_call).unwrap();
+			assert!(bound_large_call.lookup_needed());
+			let bound_small_call = Preimage::bound(small_call).unwrap();
+			assert!(!bound_small_call.lookup_needed());
+
+			let expected = vec![
+				(
+					0,
+					vec![
+						Some(ScheduledOf::<Test> {
+							maybe_id: None,
+							priority: 10,
+							call: bound_small_call.clone(),
+							maybe_periodic: None,
+							origin: root(),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						None,
+						Some(ScheduledOf::<Test> {
+							maybe_id: Some(blake2_256(&[0u8; 32])),
+							priority: 123,
+							call: bound_large_call.clone(),
+							maybe_periodic: Some((4u64, 20)),
+							origin: signed(0),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						Some(ScheduledOf::<Test> {
+							maybe_id: Some(blake2_256(&[255u8; 320])),
+							priority: 123,
+							call: Bounded::from_legacy_hash(bound_hashed_call.hash()),
+							maybe_periodic: Some((8u64, 10)),
+							origin: signed(0),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						None,
+					],
+				),
+				(
+					1,
+					vec![
+						Some(ScheduledOf::<Test> {
+							maybe_id: None,
+							priority: 11,
+							call: bound_small_call.clone(),
+							maybe_periodic: None,
+							origin: root(),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						None,
+						Some(ScheduledOf::<Test> {
+							maybe_id: Some(blake2_256(&[1u8; 32])),
+							priority: 123,
+							call: bound_large_call.clone(),
+							maybe_periodic: Some((4u64, 20)),
+							origin: signed(1),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						Some(ScheduledOf::<Test> {
+							maybe_id: Some(blake2_256(&[254u8; 320])),
+							priority: 123,
+							call: Bounded::from_legacy_hash(bound_hashed_call.hash()),
+							maybe_periodic: Some((8u64, 10)),
+							origin: signed(1),
+							_phantom: PhantomData::<u64>::default(),
+						}),
+						None,
+					],
+				),
+			];
+			for (outer, (i, j)) in x.iter().zip(expected.iter()).enumerate() {
+				assert_eq!(i.0, j.0);
+				for (inner, (x, y)) in i.1.iter().zip(j.1.iter()).enumerate() {
+					assert_eq!(x, y, "at index: outer {} inner {}", outer, inner);
+				}
+			}
+			assert_eq_uvec!(x, expected);
+
+			assert_eq!(StorageVersion::get::<Scheduler>(), 4);
+		});
+	}
+
+	#[test]
+	#[allow(deprecated)]
+	fn migration_v3_to_v4_too_large_calls_are_ignored() {
+		new_test_ext().execute_with(|| {
+			// Assume that we are at V3.
+			StorageVersion::new(3).put::<Scheduler>();
+
+			let too_large_call = RuntimeCall::System(frame_system::Call::remark {
+				remark: vec![0; <Test as Config>::Preimages::MAX_LENGTH + 1],
+			});
+
+			let i = 0u64;
+			let k = i.twox_64_concat();
+			let old = vec![Some(ScheduledV3Of::<Test> {
+				maybe_id: None,
+				priority: 1,
+				call: too_large_call.clone().into(),
+				maybe_periodic: None,
+				origin: root(),
+				_phantom: PhantomData::<u64>::default(),
+			})];
+			frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);
+
+			// The pre_upgrade hook fails:
+			let err = v3::MigrateToV4::<Test>::pre_upgrade().unwrap_err();
+			assert!(err.contains("Call is too large"));
+			// But the migration itself works:
+			let _w = v3::MigrateToV4::<Test>::on_runtime_upgrade();
+
+			let mut x = Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>();
+			x.sort_by_key(|x| x.0);
+			// The call becomes `None`.
+			let expected = vec![(0, vec![None])];
+			assert_eq_uvec!(x, expected);
+
+			assert_eq!(StorageVersion::get::<Scheduler>(), 4);
+		});
+	}
+
+	fn signed(i: u64) -> OriginCaller {
+		system::RawOrigin::Signed(i).into()
+	}
+}
diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs
index 6aaad13e4818351636ab2706640029fc458b1898..61efdfb67b73ec7daa112dad64c292edd55be3eb 100644
--- a/substrate/frame/scheduler/src/mock.rs
+++ b/substrate/frame/scheduler/src/mock.rs
@@ -124,7 +124,7 @@ parameter_types! {
 }
 impl system::Config for Test {
 	type BaseCallFilter = BaseFilter;
-	type BlockWeights = ();
+	type BlockWeights = BlockWeights;
 	type BlockLength = ();
 	type DbWeight = RocksDbWeight;
 	type RuntimeOrigin = RuntimeOrigin;
@@ -151,10 +151,6 @@ impl system::Config for Test {
 impl logger::Config for Test {
 	type RuntimeEvent = RuntimeEvent;
 }
-parameter_types! {
-	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;
-	pub const NoPreimagePostponement: Option<u64> = Some(2);
-}
 ord_parameter_types! {
 	pub const One: u64 = 1;
 }
@@ -164,11 +160,54 @@ impl pallet_preimage::Config for Test {
 	type WeightInfo = ();
 	type Currency = ();
 	type ManagerOrigin = EnsureRoot<u64>;
-	type MaxSize = ConstU32<1024>;
 	type BaseDeposit = ();
 	type ByteDeposit = ();
 }
 
+pub struct TestWeightInfo;
+impl WeightInfo for TestWeightInfo {
+	fn service_agendas_base() -> Weight {
+		Weight::from_ref_time(0b0000_0001)
+	}
+	fn service_agenda_base(i: u32) -> Weight {
+		Weight::from_ref_time((i << 8) as u64 + 0b0000_0010)
+	}
+	fn service_task_base() -> Weight {
+		Weight::from_ref_time(0b0000_0100)
+	}
+	fn service_task_periodic() -> Weight {
+		Weight::from_ref_time(0b0000_1100)
+	}
+	fn service_task_named() -> Weight {
+		Weight::from_ref_time(0b0001_0100)
+	}
+	fn service_task_fetched(s: u32) -> Weight {
+		Weight::from_ref_time((s << 8) as u64 + 0b0010_0100)
+	}
+	fn execute_dispatch_signed() -> Weight {
+		Weight::from_ref_time(0b0100_0000)
+	}
+	fn execute_dispatch_unsigned() -> Weight {
+		Weight::from_ref_time(0b1000_0000)
+	}
+	fn schedule(_s: u32) -> Weight {
+		Weight::from_ref_time(50)
+	}
+	fn cancel(_s: u32) -> Weight {
+		Weight::from_ref_time(50)
+	}
+	fn schedule_named(_s: u32) -> Weight {
+		Weight::from_ref_time(50)
+	}
+	fn cancel_named(_s: u32) -> Weight {
+		Weight::from_ref_time(50)
+	}
+}
+parameter_types! {
+	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
+		BlockWeights::get().max_block;
+}
+
 impl Config for Test {
 	type RuntimeEvent = RuntimeEvent;
 	type RuntimeOrigin = RuntimeOrigin;
@@ -177,10 +216,9 @@ impl Config for Test {
 	type MaximumWeight = MaximumSchedulerWeight;
 	type ScheduleOrigin = EitherOfDiverse<EnsureRoot<u64>, EnsureSignedBy<One, u64>>;
 	type MaxScheduledPerBlock = ConstU32<10>;
-	type WeightInfo = ();
+	type WeightInfo = TestWeightInfo;
 	type OriginPrivilegeCmp = EqualPrivilegeOnly;
-	type PreimageProvider = Preimage;
-	type NoPreimagePostponement = NoPreimagePostponement;
+	type Preimages = Preimage;
 }
 
 pub type LoggerCall = logger::Call<Test>;
diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs
index f6db70ae42d4945a2430320d0c497e43ec78e2b2..033d7879467097329d649503ad250a0bb7e193ba 100644
--- a/substrate/frame/scheduler/src/tests.rs
+++ b/substrate/frame/scheduler/src/tests.rs
@@ -23,7 +23,7 @@ use crate::mock::{
 };
 use frame_support::{
 	assert_err, assert_noop, assert_ok,
-	traits::{Contains, GetStorageVersion, OnInitialize, PreimageProvider},
+	traits::{Contains, GetStorageVersion, OnInitialize, QueryPreimage, StorePreimage},
 	Hashable,
 };
 use sp_runtime::traits::Hash;
@@ -33,9 +33,15 @@ use substrate_test_utils::assert_eq_uvec;
 fn basic_scheduling_works() {
 	new_test_ext().execute_with(|| {
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
-		assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()));
+		assert_ok!(Scheduler::do_schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap()
+		));
 		run_to_block(3);
 		assert!(logger::log().is_empty());
 		run_to_block(4);
@@ -49,51 +55,19 @@ fn basic_scheduling_works() {
 fn scheduling_with_preimages_works() {
 	new_test_ext().execute_with(|| {
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		let hash = <Test as frame_system::Config>::Hashing::hash_of(&call);
-		let hashed = MaybeHashed::Hash(hash);
+		let len = call.using_encoded(|x| x.len()) as u32;
+		let hashed = Preimage::pick(hash, len);
 		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode()));
 		assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed));
-		assert!(Preimage::preimage_requested(&hash));
+		assert!(Preimage::is_requested(&hash));
 		run_to_block(3);
 		assert!(logger::log().is_empty());
 		run_to_block(4);
-		assert!(!Preimage::have_preimage(&hash));
-		assert!(!Preimage::preimage_requested(&hash));
-		assert_eq!(logger::log(), vec![(root(), 42u32)]);
-		run_to_block(100);
-		assert_eq!(logger::log(), vec![(root(), 42u32)]);
-	});
-}
-
-#[test]
-fn scheduling_with_preimage_postpones_correctly() {
-	new_test_ext().execute_with(|| {
-		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
-		let hash = <Test as frame_system::Config>::Hashing::hash_of(&call);
-		let hashed = MaybeHashed::Hash(hash);
-
-		assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed));
-		assert!(Preimage::preimage_requested(&hash));
-
-		run_to_block(4);
-		// #4 empty due to no preimage
-		assert!(logger::log().is_empty());
-
-		// Register preimage.
-		assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode()));
-
-		run_to_block(5);
-		// #5 empty since postponement is 2 blocks.
-		assert!(logger::log().is_empty());
-
-		run_to_block(6);
-		// #6 is good.
+		assert!(!Preimage::len(&hash).is_some());
+		assert!(!Preimage::is_requested(&hash));
 		assert_eq!(logger::log(), vec![(root(), 42u32)]);
-		assert!(!Preimage::have_preimage(&hash));
-		assert!(!Preimage::preimage_requested(&hash));
-
 		run_to_block(100);
 		assert_eq!(logger::log(), vec![(root(), 42u32)]);
 	});
@@ -104,10 +78,16 @@ fn schedule_after_works() {
 	new_test_ext().execute_with(|| {
 		run_to_block(2);
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
 		// This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6
-		assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into()));
+		assert_ok!(Scheduler::do_schedule(
+			DispatchTime::After(3),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap()
+		));
 		run_to_block(5);
 		assert!(logger::log().is_empty());
 		run_to_block(6);
@@ -122,9 +102,15 @@ fn schedule_after_zero_works() {
 	new_test_ext().execute_with(|| {
 		run_to_block(2);
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
-		assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into()));
+		assert_ok!(Scheduler::do_schedule(
+			DispatchTime::After(0),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap()
+		));
 		// Will trigger on the next block.
 		run_to_block(3);
 		assert_eq!(logger::log(), vec![(root(), 42u32)]);
@@ -142,8 +128,11 @@ fn periodic_scheduling_works() {
 			Some((3, 3)),
 			127,
 			root(),
-			RuntimeCall::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into()
+			Preimage::bound(RuntimeCall::Logger(logger::Call::log {
+				i: 42,
+				weight: Weight::from_ref_time(10)
+			}))
+			.unwrap()
 		));
 		run_to_block(3);
 		assert!(logger::log().is_empty());
@@ -166,10 +155,17 @@ fn periodic_scheduling_works() {
 fn reschedule_works() {
 	new_test_ext().execute_with(|| {
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
 		assert_eq!(
-			Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(),
+			Scheduler::do_schedule(
+				DispatchTime::At(4),
+				None,
+				127,
+				root(),
+				Preimage::bound(call).unwrap()
+			)
+			.unwrap(),
 			(4, 0)
 		);
 
@@ -198,16 +194,16 @@ fn reschedule_works() {
 fn reschedule_named_works() {
 	new_test_ext().execute_with(|| {
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
 		assert_eq!(
 			Scheduler::do_schedule_named(
-				1u32.encode(),
+				[1u8; 32],
 				DispatchTime::At(4),
 				None,
 				127,
 				root(),
-				call.into(),
+				Preimage::bound(call).unwrap(),
 			)
 			.unwrap(),
 			(4, 0)
@@ -216,13 +212,10 @@ fn reschedule_named_works() {
 		run_to_block(3);
 		assert!(logger::log().is_empty());
 
-		assert_eq!(
-			Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(),
-			(6, 0)
-		);
+		assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0));
 
 		assert_noop!(
-			Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)),
+			Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)),
 			Error::<Test>::RescheduleNoChange
 		);
 
@@ -241,16 +234,16 @@ fn reschedule_named_works() {
 fn reschedule_named_perodic_works() {
 	new_test_ext().execute_with(|| {
 		let call =
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
 		assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));
 		assert_eq!(
 			Scheduler::do_schedule_named(
-				1u32.encode(),
+				[1u8; 32],
 				DispatchTime::At(4),
 				Some((3, 3)),
 				127,
 				root(),
-				call.into(),
+				Preimage::bound(call).unwrap(),
 			)
 			.unwrap(),
 			(4, 0)
@@ -259,14 +252,8 @@ fn reschedule_named_perodic_works() {
 		run_to_block(3);
 		assert!(logger::log().is_empty());
 
-		assert_eq!(
-			Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(),
-			(5, 0)
-		);
-		assert_eq!(
-			Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(),
-			(6, 0)
-		);
+		assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(5)).unwrap(), (5, 0));
+		assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0));
 
 		run_to_block(5);
 		assert!(logger::log().is_empty());
@@ -275,7 +262,7 @@ fn reschedule_named_perodic_works() {
 		assert_eq!(logger::log(), vec![(root(), 42u32)]);
 
 		assert_eq!(
-			Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(),
+			Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(10)).unwrap(),
 			(10, 0)
 		);
 
@@ -298,13 +285,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() {
 	new_test_ext().execute_with(|| {
 		// at #4.
 		Scheduler::do_schedule_named(
-			1u32.encode(),
+			[1u8; 32],
 			DispatchTime::At(4),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
+			Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+				i: 69,
+				weight: Weight::from_ref_time(10),
+			}))
+			.unwrap(),
 		)
 		.unwrap();
 		let i = Scheduler::do_schedule(
@@ -312,13 +302,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() {
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
+			Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+				i: 42,
+				weight: Weight::from_ref_time(10),
+			}))
+			.unwrap(),
 		)
 		.unwrap();
 		run_to_block(3);
 		assert!(logger::log().is_empty());
-		assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));
+		assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));
 		assert_ok!(Scheduler::do_cancel(None, i));
 		run_to_block(100);
 		assert!(logger::log().is_empty());
@@ -330,35 +323,44 @@ fn cancel_named_periodic_scheduling_works() {
 	new_test_ext().execute_with(|| {
 		// at #4, every 3 blocks, 3 times.
 		Scheduler::do_schedule_named(
-			1u32.encode(),
+			[1u8; 32],
 			DispatchTime::At(4),
 			Some((3, 3)),
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
+			Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+				i: 42,
+				weight: Weight::from_ref_time(10),
+			}))
+			.unwrap(),
 		)
 		.unwrap();
 		// same id results in error.
 		assert!(Scheduler::do_schedule_named(
-			1u32.encode(),
+			[1u8; 32],
 			DispatchTime::At(4),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
+			Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+				i: 69,
+				weight: Weight::from_ref_time(10)
+			}))
+			.unwrap(),
 		)
 		.is_err());
 		// different id is ok.
 		Scheduler::do_schedule_named(
-			2u32.encode(),
+			[2u8; 32],
 			DispatchTime::At(8),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
+			Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+				i: 69,
+				weight: Weight::from_ref_time(10),
+			}))
+			.unwrap(),
 		)
 		.unwrap();
 		run_to_block(3);
@@ -366,7 +368,7 @@ fn cancel_named_periodic_scheduling_works() {
 		run_to_block(4);
 		assert_eq!(logger::log(), vec![(root(), 42u32)]);
 		run_to_block(6);
-		assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));
+		assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));
 		run_to_block(100);
 		assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);
 	});
@@ -374,28 +376,23 @@ fn cancel_named_periodic_scheduling_works() {
 
 #[test]
 fn scheduler_respects_weight_limits() {
+	let max_weight: Weight = <Test as Config>::MaximumWeight::get();
 	new_test_ext().execute_with(|| {
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 42,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 69,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
 		// 69 and 42 do not fit together
 		run_to_block(4);
@@ -405,62 +402,128 @@ fn scheduler_respects_weight_limits() {
 	});
 }
 
+/// Permanently overweight calls are not deleted but also not executed.
 #[test]
-fn scheduler_respects_hard_deadlines_more() {
+fn scheduler_does_not_delete_permanently_overweight_call() {
+	let max_weight: Weight = <Test as Config>::MaximumWeight::get();
 	new_test_ext().execute_with(|| {
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
-			0,
+			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 42,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		// Never executes.
+		run_to_block(100);
+		assert_eq!(logger::log(), vec![]);
+
+		// Assert the `PermanentlyOverweight` event.
+		assert_eq!(
+			System::events().last().unwrap().event,
+			crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(),
+		);
+		// The call is still in the agenda.
+		assert!(Agenda::<Test>::get(4)[0].is_some());
+	});
+}
+
+#[test]
+fn scheduler_handles_periodic_failure() {
+	let max_weight: Weight = <Test as Config>::MaximumWeight::get();
+	let max_per_block = <Test as Config>::MaxScheduledPerBlock::get();
+
+	new_test_ext().execute_with(|| {
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });
+		let bound = Preimage::bound(call).unwrap();
+
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
-			None,
-			0,
+			Some((4, u32::MAX)),
+			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 69,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			bound.clone(),
+		));
+		// Executes 5 times till block 20.
+		run_to_block(20);
+		assert_eq!(logger::log().len(), 5);
+
+		// Block 28 will already be full.
+		for _ in 0..max_per_block {
+			assert_ok!(Scheduler::do_schedule(
+				DispatchTime::At(28),
+				None,
+				120,
+				root(),
+				bound.clone(),
+			));
+		}
+
+		// Going to block 24 will emit a `PeriodicFailed` event.
+		run_to_block(24);
+		assert_eq!(logger::log().len(), 6);
+
+		assert_eq!(
+			System::events().last().unwrap().event,
+			crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(),
+		);
+	});
+}
+
+#[test]
+fn scheduler_handles_periodic_unavailable_preimage() {
+	let max_weight: Weight = <Test as Config>::MaximumWeight::get();
+
+	new_test_ext().execute_with(|| {
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });
+		let hash = <Test as frame_system::Config>::Hashing::hash_of(&call);
+		let len = call.using_encoded(|x| x.len()) as u32;
+		let bound = Preimage::pick(hash, len);
+		assert_ok!(Preimage::note(call.encode().into()));
+
+		assert_ok!(Scheduler::do_schedule(
+			DispatchTime::At(4),
+			Some((4, u32::MAX)),
+			127,
+			root(),
+			bound.clone(),
 		));
-		// With base weights, 69 and 42 should not fit together, but do because of hard
-		// deadlines
+		// Executes 1 times till block 4.
 		run_to_block(4);
-		assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);
+		assert_eq!(logger::log().len(), 1);
+
+		// Unnote the preimage.
+		Preimage::unnote(&hash);
+
+		// Does not ever execute again.
+		run_to_block(100);
+		assert_eq!(logger::log().len(), 1);
+
+		// The preimage is not requested anymore.
+		assert!(!Preimage::is_requested(&hash));
 	});
 }
 
 #[test]
 fn scheduler_respects_priority_ordering() {
+	let max_weight: Weight = <Test as Config>::MaximumWeight::get();
 	new_test_ext().execute_with(|| {
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			1,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 42,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			0,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 69,
-				weight: MaximumSchedulerWeight::get() / 2
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
 		run_to_block(4);
 		assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]);
@@ -470,35 +533,30 @@ fn scheduler_respects_priority_ordering() {
 #[test]
 fn scheduler_respects_priority_ordering_with_soft_deadlines() {
 	new_test_ext().execute_with(|| {
-		let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0);
-		let item_weight =
-			<() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0);
+		let max_weight: Weight = <Test as Config>::MaximumWeight::get();
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			255,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight })
-				.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight })
-				.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 });
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(4),
 			None,
 			126,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 2600,
-				weight: max_weight / 2 - item_weight + Weight::from_ref_time(1)
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
 
 		// 2600 does not fit with 69 or 42, but has higher priority, so will go through
@@ -513,90 +571,96 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() {
 #[test]
 fn on_initialize_weight_is_correct() {
 	new_test_ext().execute_with(|| {
-		let base_weight = <() as WeightInfo>::on_initialize(0);
-		let call_weight = MaximumSchedulerWeight::get() / 4;
+		let call_weight = Weight::from_ref_time(25);
 
 		// Named
+		let call = RuntimeCall::Logger(LoggerCall::log {
+			i: 3,
+			weight: call_weight + Weight::from_ref_time(1),
+		});
 		assert_ok!(Scheduler::do_schedule_named(
-			1u32.encode(),
+			[1u8; 32],
 			DispatchTime::At(3),
 			None,
 			255,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 3,
-				weight: call_weight + Weight::from_ref_time(1)
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: call_weight + Weight::from_ref_time(2),
+		});
 		// Anon Periodic
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(2),
 			Some((1000, 3)),
 			128,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 42,
-				weight: call_weight + Weight::from_ref_time(2)
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
+		let call = RuntimeCall::Logger(LoggerCall::log {
+			i: 69,
+			weight: call_weight + Weight::from_ref_time(3),
+		});
 		// Anon
 		assert_ok!(Scheduler::do_schedule(
 			DispatchTime::At(2),
 			None,
 			127,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 69,
-				weight: call_weight + Weight::from_ref_time(3)
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
 		// Named Periodic
+		let call = RuntimeCall::Logger(LoggerCall::log {
+			i: 2600,
+			weight: call_weight + Weight::from_ref_time(4),
+		});
 		assert_ok!(Scheduler::do_schedule_named(
-			2u32.encode(),
+			[2u8; 32],
 			DispatchTime::At(1),
 			Some((1000, 3)),
 			126,
 			root(),
-			RuntimeCall::Logger(LoggerCall::log {
-				i: 2600,
-				weight: call_weight + Weight::from_ref_time(4)
-			})
-			.into(),
+			Preimage::bound(call).unwrap(),
 		));
 
 		// Will include the named periodic only
-		let actual_weight = Scheduler::on_initialize(1);
 		assert_eq!(
-			actual_weight,
-			base_weight +
-				call_weight + Weight::from_ref_time(4) +
-				<() as MarginalWeightInfo>::item(true, true, Some(false))
+			Scheduler::on_initialize(1),
+			TestWeightInfo::service_agendas_base() +
+				TestWeightInfo::service_agenda_base(1) +
+				<TestWeightInfo as MarginalWeightInfo>::service_task(None, true, true) +
+				TestWeightInfo::execute_dispatch_unsigned() +
+				call_weight + Weight::from_ref_time(4)
 		);
+		assert_eq!(IncompleteSince::<Test>::get(), None);
 		assert_eq!(logger::log(), vec![(root(), 2600u32)]);
 
 		// Will include anon and anon periodic
-		let actual_weight = Scheduler::on_initialize(2);
 		assert_eq!(
-			actual_weight,
-			base_weight +
-				call_weight + Weight::from_ref_time(2) +
-				<() as MarginalWeightInfo>::item(false, false, Some(false)) +
+			Scheduler::on_initialize(2),
+			TestWeightInfo::service_agendas_base() +
+				TestWeightInfo::service_agenda_base(2) +
+				<TestWeightInfo as MarginalWeightInfo>::service_task(None, false, true) +
+				TestWeightInfo::execute_dispatch_unsigned() +
 				call_weight + Weight::from_ref_time(3) +
-				<() as MarginalWeightInfo>::item(true, false, Some(false))
+				<TestWeightInfo as MarginalWeightInfo>::service_task(None, false, false) +
+				TestWeightInfo::execute_dispatch_unsigned() +
+				call_weight + Weight::from_ref_time(2)
 		);
+		assert_eq!(IncompleteSince::<Test>::get(), None);
 		assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);
 
 		// Will include named only
-		let actual_weight = Scheduler::on_initialize(3);
 		assert_eq!(
-			actual_weight,
-			base_weight +
-				call_weight + Weight::from_ref_time(1) +
-				<() as MarginalWeightInfo>::item(false, true, Some(false))
+			Scheduler::on_initialize(3),
+			TestWeightInfo::service_agendas_base() +
+				TestWeightInfo::service_agenda_base(1) +
+				<TestWeightInfo as MarginalWeightInfo>::service_task(None, true, false) +
+				TestWeightInfo::execute_dispatch_unsigned() +
+				call_weight + Weight::from_ref_time(1)
 		);
+		assert_eq!(IncompleteSince::<Test>::get(), None);
 		assert_eq!(
 			logger::log(),
 			vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)]
@@ -604,35 +668,33 @@ fn on_initialize_weight_is_correct() {
 
 		// Will contain none
 		let actual_weight = Scheduler::on_initialize(4);
-		assert_eq!(actual_weight, base_weight);
+		assert_eq!(
+			actual_weight,
+			TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0)
+		);
 	});
 }
 
 #[test]
 fn root_calls_works() {
 	new_test_ext().execute_with(|| {
-		let call = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		let call2 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
+		let call = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 69,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
+		assert_ok!(
+			Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call,)
 		);
-		assert_ok!(Scheduler::schedule_named(
-			RuntimeOrigin::root(),
-			1u32.encode(),
-			4,
-			None,
-			127,
-			call,
-		));
 		assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call2));
 		run_to_block(3);
 		// Scheduled calls are in the agenda.
 		assert_eq!(Agenda::<Test>::get(4).len(), 2);
 		assert!(logger::log().is_empty());
-		assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), 1u32.encode()));
+		assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32]));
 		assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1));
 		// Scheduled calls are made NONE, so should not effect state
 		run_to_block(100);
@@ -645,29 +707,30 @@ fn fails_to_schedule_task_in_the_past() {
 	new_test_ext().execute_with(|| {
 		run_to_block(3);
 
-		let call1 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		let call2 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		let call3 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		assert_err!(
-			Scheduler::schedule_named(RuntimeOrigin::root(), 1u32.encode(), 2, None, 127, call1),
+		let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 69,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
+
+		assert_noop!(
+			Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, 127, call1),
 			Error::<Test>::TargetBlockNumberInPast,
 		);
 
-		assert_err!(
+		assert_noop!(
 			Scheduler::schedule(RuntimeOrigin::root(), 2, None, 127, call2),
 			Error::<Test>::TargetBlockNumberInPast,
 		);
 
-		assert_err!(
+		assert_noop!(
 			Scheduler::schedule(RuntimeOrigin::root(), 3, None, 127, call3),
 			Error::<Test>::TargetBlockNumberInPast,
 		);
@@ -675,19 +738,19 @@ fn fails_to_schedule_task_in_the_past() {
 }
 
 #[test]
-fn should_use_orign() {
+fn should_use_origin() {
 	new_test_ext().execute_with(|| {
-		let call = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		let call2 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
+		let call = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 69,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
 		assert_ok!(Scheduler::schedule_named(
 			system::RawOrigin::Signed(1).into(),
-			1u32.encode(),
+			[1u8; 32],
 			4,
 			None,
 			127,
@@ -698,7 +761,7 @@ fn should_use_orign() {
 		// Scheduled calls are in the agenda.
 		assert_eq!(Agenda::<Test>::get(4).len(), 2);
 		assert!(logger::log().is_empty());
-		assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode()));
+		assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32]));
 		assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1));
 		// Scheduled calls are made NONE, so should not effect state
 		run_to_block(100);
@@ -707,20 +770,20 @@ fn should_use_orign() {
 }
 
 #[test]
-fn should_check_orign() {
+fn should_check_origin() {
 	new_test_ext().execute_with(|| {
-		let call = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
-		let call2 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) })
-				.into(),
-		);
+		let call = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 69,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
 		assert_noop!(
 			Scheduler::schedule_named(
 				system::RawOrigin::Signed(2).into(),
-				1u32.encode(),
+				[1u8; 32],
 				4,
 				None,
 				127,
@@ -736,25 +799,19 @@ fn should_check_orign() {
 }
 
 #[test]
-fn should_check_orign_for_cancel() {
+fn should_check_origin_for_cancel() {
 	new_test_ext().execute_with(|| {
-		let call = Box::new(
-			RuntimeCall::Logger(LoggerCall::log_without_filter {
-				i: 69,
-				weight: Weight::from_ref_time(1000),
-			})
-			.into(),
-		);
-		let call2 = Box::new(
-			RuntimeCall::Logger(LoggerCall::log_without_filter {
-				i: 42,
-				weight: Weight::from_ref_time(1000),
-			})
-			.into(),
-		);
+		let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {
+			i: 69,
+			weight: Weight::from_ref_time(10),
+		}));
+		let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {
+			i: 42,
+			weight: Weight::from_ref_time(10),
+		}));
 		assert_ok!(Scheduler::schedule_named(
 			system::RawOrigin::Signed(1).into(),
-			1u32.encode(),
+			[1u8; 32],
 			4,
 			None,
 			127,
@@ -766,14 +823,11 @@ fn should_check_orign_for_cancel() {
 		assert_eq!(Agenda::<Test>::get(4).len(), 2);
 		assert!(logger::log().is_empty());
 		assert_noop!(
-			Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()),
+			Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]),
 			BadOrigin
 		);
 		assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin);
-		assert_noop!(
-			Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()),
-			BadOrigin
-		);
+		assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin);
 		assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin);
 		run_to_block(5);
 		assert_eq!(
@@ -787,7 +841,7 @@ fn should_check_orign_for_cancel() {
 }
 
 #[test]
-fn migration_to_v3_works() {
+fn migration_to_v4_works() {
 	new_test_ext().execute_with(|| {
 		for i in 0..3u64 {
 			let k = i.twox_64_concat();
@@ -807,7 +861,7 @@ fn migration_to_v3_works() {
 					priority: 123,
 					call: RuntimeCall::Logger(LoggerCall::log {
 						i: 69,
-						weight: Weight::from_ref_time(1000),
+						weight: Weight::from_ref_time(10),
 					}),
 					maybe_periodic: Some((456u64, 10)),
 				}),
@@ -815,103 +869,109 @@ fn migration_to_v3_works() {
 			frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);
 		}
 
-		Scheduler::migrate_v1_to_v3();
-
-		assert_eq_uvec!(
-			Agenda::<Test>::iter().collect::<Vec<_>>(),
-			vec![
-				(
-					0,
-					vec![
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: None,
-							priority: 10,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 96,
-								weight: Weight::from_ref_time(100)
-							})
-							.into(),
-							maybe_periodic: None,
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-						None,
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: Some(b"test".to_vec()),
-							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
-							maybe_periodic: Some((456u64, 10)),
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-					]
-				),
-				(
-					1,
-					vec![
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: None,
-							priority: 11,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 96,
-								weight: Weight::from_ref_time(100)
-							})
-							.into(),
-							maybe_periodic: None,
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-						None,
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: Some(b"test".to_vec()),
-							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
-							maybe_periodic: Some((456u64, 10)),
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-					]
-				),
-				(
-					2,
-					vec![
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: None,
-							priority: 12,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 96,
-								weight: Weight::from_ref_time(100)
-							})
-							.into(),
-							maybe_periodic: None,
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-						None,
-						Some(ScheduledV3Of::<Test> {
-							maybe_id: Some(b"test".to_vec()),
-							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
-								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
-							maybe_periodic: Some((456u64, 10)),
-							origin: root(),
-							_phantom: PhantomData::<u64>::default(),
-						}),
-					]
-				)
-			]
-		);
+		Scheduler::migrate_v1_to_v4();
+
+		let mut x = Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>();
+		x.sort_by_key(|x| x.0);
+		let expected = vec![
+			(
+				0,
+				vec![
+					Some(ScheduledOf::<Test> {
+						maybe_id: None,
+						priority: 10,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 96,
+							weight: Weight::from_ref_time(100),
+						}))
+						.unwrap(),
+						maybe_periodic: None,
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					None,
+					Some(ScheduledOf::<Test> {
+						maybe_id: Some(blake2_256(&b"test"[..])),
+						priority: 123,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 69,
+							weight: Weight::from_ref_time(10),
+						}))
+						.unwrap(),
+						maybe_periodic: Some((456u64, 10)),
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+				],
+			),
+			(
+				1,
+				vec![
+					Some(ScheduledOf::<Test> {
+						maybe_id: None,
+						priority: 11,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 96,
+							weight: Weight::from_ref_time(100),
+						}))
+						.unwrap(),
+						maybe_periodic: None,
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					None,
+					Some(ScheduledOf::<Test> {
+						maybe_id: Some(blake2_256(&b"test"[..])),
+						priority: 123,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 69,
+							weight: Weight::from_ref_time(10),
+						}))
+						.unwrap(),
+						maybe_periodic: Some((456u64, 10)),
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+				],
+			),
+			(
+				2,
+				vec![
+					Some(ScheduledOf::<Test> {
+						maybe_id: None,
+						priority: 12,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 96,
+							weight: Weight::from_ref_time(100),
+						}))
+						.unwrap(),
+						maybe_periodic: None,
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+					None,
+					Some(ScheduledOf::<Test> {
+						maybe_id: Some(blake2_256(&b"test"[..])),
+						priority: 123,
+						call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
+							i: 69,
+							weight: Weight::from_ref_time(10),
+						}))
+						.unwrap(),
+						maybe_periodic: Some((456u64, 10)),
+						origin: root(),
+						_phantom: PhantomData::<u64>::default(),
+					}),
+				],
+			),
+		];
+		for (i, j) in x.iter().zip(expected.iter()) {
+			assert_eq!(i.0, j.0);
+			for (x, y) in i.1.iter().zip(j.1.iter()) {
+				assert_eq!(x, y);
+			}
+		}
+		assert_eq_uvec!(x, expected);
 
 		assert_eq!(Scheduler::current_storage_version(), 3);
 	});
@@ -922,29 +982,29 @@ fn test_migrate_origin() {
 	new_test_ext().execute_with(|| {
 		for i in 0..3u64 {
 			let k = i.twox_64_concat();
-			let old: Vec<Option<Scheduled<CallOrHashOf<Test>, u64, u32, u64>>> = vec![
+			let old: Vec<Option<Scheduled<[u8; 32], Bounded<RuntimeCall>, u64, u32, u64>>> = vec![
 				Some(Scheduled {
 					maybe_id: None,
 					priority: i as u8 + 10,
-					call: RuntimeCall::Logger(LoggerCall::log {
+					call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 						i: 96,
 						weight: Weight::from_ref_time(100),
-					})
-					.into(),
+					}))
+					.unwrap(),
 					origin: 3u32,
 					maybe_periodic: None,
 					_phantom: Default::default(),
 				}),
 				None,
 				Some(Scheduled {
-					maybe_id: Some(b"test".to_vec()),
+					maybe_id: Some(blake2_256(&b"test"[..])),
 					priority: 123,
 					origin: 2u32,
-					call: RuntimeCall::Logger(LoggerCall::log {
+					call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 						i: 69,
-						weight: Weight::from_ref_time(1000),
-					})
-					.into(),
+						weight: Weight::from_ref_time(10),
+					}))
+					.unwrap(),
 					maybe_periodic: Some((456u64, 10)),
 					_phantom: Default::default(),
 				}),
@@ -965,32 +1025,32 @@ fn test_migrate_origin() {
 		Scheduler::migrate_origin::<u32>();
 
 		assert_eq_uvec!(
-			Agenda::<Test>::iter().collect::<Vec<_>>(),
+			Agenda::<Test>::iter().map(|x| (x.0, x.1.into_inner())).collect::<Vec<_>>(),
 			vec![
 				(
 					0,
 					vec![
-						Some(ScheduledV2::<CallOrHashOf<Test>, u64, OriginCaller, u64> {
+						Some(ScheduledOf::<Test> {
 							maybe_id: None,
 							priority: 10,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 96,
 								weight: Weight::from_ref_time(100)
-							})
-							.into(),
+							}))
+							.unwrap(),
 							maybe_periodic: None,
 							origin: system::RawOrigin::Root.into(),
 							_phantom: PhantomData::<u64>::default(),
 						}),
 						None,
-						Some(ScheduledV2 {
-							maybe_id: Some(b"test".to_vec()),
+						Some(Scheduled {
+							maybe_id: Some(blake2_256(&b"test"[..])),
 							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
+								weight: Weight::from_ref_time(10)
+							}))
+							.unwrap(),
 							maybe_periodic: Some((456u64, 10)),
 							origin: system::RawOrigin::None.into(),
 							_phantom: PhantomData::<u64>::default(),
@@ -1000,27 +1060,27 @@ fn test_migrate_origin() {
 				(
 					1,
 					vec![
-						Some(ScheduledV2 {
+						Some(Scheduled {
 							maybe_id: None,
 							priority: 11,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 96,
 								weight: Weight::from_ref_time(100)
-							})
-							.into(),
+							}))
+							.unwrap(),
 							maybe_periodic: None,
 							origin: system::RawOrigin::Root.into(),
 							_phantom: PhantomData::<u64>::default(),
 						}),
 						None,
-						Some(ScheduledV2 {
-							maybe_id: Some(b"test".to_vec()),
+						Some(Scheduled {
+							maybe_id: Some(blake2_256(&b"test"[..])),
 							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
+								weight: Weight::from_ref_time(10)
+							}))
+							.unwrap(),
 							maybe_periodic: Some((456u64, 10)),
 							origin: system::RawOrigin::None.into(),
 							_phantom: PhantomData::<u64>::default(),
@@ -1030,27 +1090,27 @@ fn test_migrate_origin() {
 				(
 					2,
 					vec![
-						Some(ScheduledV2 {
+						Some(Scheduled {
 							maybe_id: None,
 							priority: 12,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 96,
 								weight: Weight::from_ref_time(100)
-							})
-							.into(),
+							}))
+							.unwrap(),
 							maybe_periodic: None,
 							origin: system::RawOrigin::Root.into(),
 							_phantom: PhantomData::<u64>::default(),
 						}),
 						None,
-						Some(ScheduledV2 {
-							maybe_id: Some(b"test".to_vec()),
+						Some(Scheduled {
+							maybe_id: Some(blake2_256(&b"test"[..])),
 							priority: 123,
-							call: RuntimeCall::Logger(LoggerCall::log {
+							call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log {
 								i: 69,
-								weight: Weight::from_ref_time(1000)
-							})
-							.into(),
+								weight: Weight::from_ref_time(10)
+							}))
+							.unwrap(),
 							maybe_periodic: Some((456u64, 10)),
 							origin: system::RawOrigin::None.into(),
 							_phantom: PhantomData::<u64>::default(),
@@ -1061,3 +1121,649 @@ fn test_migrate_origin() {
 		);
 	});
 }
+
+#[test]
+fn postponed_named_task_cannot_be_rescheduled() {
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) });
+		let hash = <Test as frame_system::Config>::Hashing::hash_of(&call);
+		let len = call.using_encoded(|x| x.len()) as u32;
+		let hashed = Preimage::pick(hash, len);
+		let name: [u8; 32] = hash.as_ref().try_into().unwrap();
+
+		let address = Scheduler::do_schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			hashed.clone(),
+		)
+		.unwrap();
+		assert!(Preimage::is_requested(&hash));
+		assert!(Lookup::<Test>::contains_key(name));
+
+		// Run to a very large block.
+		run_to_block(10);
+		// It was not executed.
+		assert!(logger::log().is_empty());
+		assert!(Preimage::is_requested(&hash));
+		// Postponing removes the lookup.
+		assert!(!Lookup::<Test>::contains_key(name));
+
+		// The agenda still contains the call.
+		let agenda = Agenda::<Test>::iter().collect::<Vec<_>>();
+		assert_eq!(agenda.len(), 1);
+		assert_eq!(
+			agenda[0].1,
+			vec![Some(Scheduled {
+				maybe_id: Some(name),
+				priority: 127,
+				call: hashed,
+				maybe_periodic: None,
+				origin: root().into(),
+				_phantom: Default::default(),
+			})]
+		);
+
+		// Finally add the preimage.
+		assert_ok!(Preimage::note(call.encode().into()));
+		run_to_block(1000);
+		// It did not execute.
+		assert!(logger::log().is_empty());
+		assert!(Preimage::is_requested(&hash));
+
+		// Manually re-schedule the call by name does not work.
+		assert_err!(
+			Scheduler::do_reschedule_named(name, DispatchTime::At(1001)),
+			Error::<Test>::NotFound
+		);
+		// Manually re-scheduling the call by address errors.
+		assert_err!(
+			Scheduler::do_reschedule(address, DispatchTime::At(1001)),
+			Error::<Test>::Named
+		);
+	});
+}
+
+/// Using the scheduler as `v3::Anon` works.
+#[test]
+fn scheduler_v3_anon_basic_works() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+
+		// Schedule a call.
+		let _address = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+		// Executes in block 4.
+		run_to_block(4);
+		assert_eq!(logger::log(), vec![(root(), 42u32)]);
+		// ... but not again.
+		run_to_block(100);
+		assert_eq!(logger::log(), vec![(root(), 42u32)]);
+	});
+}
+
+#[test]
+fn scheduler_v3_anon_cancel_works() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+
+		// Schedule a call.
+		let address = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+		// Cancel the call.
+		assert_ok!(<Scheduler as Anon<_, _, _>>::cancel(address));
+		// It did not get executed.
+		run_to_block(100);
+		assert!(logger::log().is_empty());
+		// Cannot cancel again.
+		assert_err!(<Scheduler as Anon<_, _, _>>::cancel(address), DispatchError::Unavailable);
+	});
+}
+
+#[test]
+fn scheduler_v3_anon_reschedule_works() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+
+		// Schedule a call.
+		let address = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+
+		// Cannot re-schedule into the same block.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(4)),
+			Error::<Test>::RescheduleNoChange
+		);
+		// Cannot re-schedule into the past.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(3)),
+			Error::<Test>::TargetBlockNumberInPast
+		);
+		// Re-schedule to block 5.
+		assert_ok!(<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(5)));
+		// Scheduled for block 5.
+		run_to_block(4);
+		assert!(logger::log().is_empty());
+		run_to_block(5);
+		// Does execute in block 5.
+		assert_eq!(logger::log(), vec![(root(), 42)]);
+		// Cannot re-schedule executed task.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(10)),
+			DispatchError::Unavailable
+		);
+	});
+}
+
+/// Cancelling a call and then scheduling a second call for the same
+/// block results in different addresses.
+#[test]
+fn scheduler_v3_anon_schedule_does_not_resuse_addr() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+
+		// Schedule both calls.
+		let addr_1 = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call.clone()).unwrap(),
+		)
+		.unwrap();
+		// Cancel the call.
+		assert_ok!(<Scheduler as Anon<_, _, _>>::cancel(addr_1));
+		let addr_2 = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+
+		// Should not re-use the address.
+		assert!(addr_1 != addr_2);
+	});
+}
+
+#[test]
+fn scheduler_v3_anon_next_schedule_time_works() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+
+		// Schedule a call.
+		let address = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+
+		// Scheduled for block 4.
+		assert_eq!(<Scheduler as Anon<_, _, _>>::next_dispatch_time(address), Ok(4));
+		// Block 4 executes it.
+		run_to_block(4);
+		assert_eq!(logger::log(), vec![(root(), 42)]);
+
+		// It has no dispatch time anymore.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::next_dispatch_time(address),
+			DispatchError::Unavailable
+		);
+	});
+}
+
+/// Re-scheduling a task changes its next dispatch time.
+#[test]
+fn scheduler_v3_anon_reschedule_and_next_schedule_time_work() {
+	use frame_support::traits::schedule::v3::Anon;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+
+		// Schedule a call.
+		let old_address = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+
+		// Scheduled for block 4.
+		assert_eq!(<Scheduler as Anon<_, _, _>>::next_dispatch_time(old_address), Ok(4));
+		// Re-schedule to block 5.
+		let address =
+			<Scheduler as Anon<_, _, _>>::reschedule(old_address, DispatchTime::At(5)).unwrap();
+		assert!(address != old_address);
+		// Scheduled for block 5.
+		assert_eq!(<Scheduler as Anon<_, _, _>>::next_dispatch_time(address), Ok(5));
+
+		// Block 4 does nothing.
+		run_to_block(4);
+		assert!(logger::log().is_empty());
+		// Block 5 executes it.
+		run_to_block(5);
+		assert_eq!(logger::log(), vec![(root(), 42)]);
+	});
+}
+
+#[test]
+fn scheduler_v3_anon_schedule_agenda_overflows() {
+	use frame_support::traits::schedule::v3::Anon;
+	let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();
+
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+
+		// Schedule the maximal number allowed per block.
+		for _ in 0..max {
+			<Scheduler as Anon<_, _, _>>::schedule(
+				DispatchTime::At(4),
+				None,
+				127,
+				root(),
+				bound.clone(),
+			)
+			.unwrap();
+		}
+
+		// One more time and it errors.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::schedule(DispatchTime::At(4), None, 127, root(), bound,),
+			DispatchError::Exhausted
+		);
+
+		run_to_block(4);
+		// All scheduled calls are executed.
+		assert_eq!(logger::log().len() as u32, max);
+	});
+}
+
+/// Cancelling and scheduling does not overflow the agenda but fills holes.
+#[test]
+fn scheduler_v3_anon_cancel_and_schedule_fills_holes() {
+	use frame_support::traits::schedule::v3::Anon;
+	let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();
+	assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3");
+
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+		let mut addrs = Vec::<_>::default();
+
+		// Schedule the maximal number allowed per block.
+		for _ in 0..max {
+			addrs.push(
+				<Scheduler as Anon<_, _, _>>::schedule(
+					DispatchTime::At(4),
+					None,
+					127,
+					root(),
+					bound.clone(),
+				)
+				.unwrap(),
+			);
+		}
+		// Cancel three of them.
+		for addr in addrs.into_iter().take(3) {
+			<Scheduler as Anon<_, _, _>>::cancel(addr).unwrap();
+		}
+		// Schedule three new ones.
+		for i in 0..3 {
+			let (_block, index) = <Scheduler as Anon<_, _, _>>::schedule(
+				DispatchTime::At(4),
+				None,
+				127,
+				root(),
+				bound.clone(),
+			)
+			.unwrap();
+			assert_eq!(i, index);
+		}
+
+		run_to_block(4);
+		// Maximum number of calls are executed.
+		assert_eq!(logger::log().len() as u32, max);
+	});
+}
+
+/// Re-scheduling does not overflow the agenda but fills holes.
+#[test]
+fn scheduler_v3_anon_reschedule_fills_holes() {
+	use frame_support::traits::schedule::v3::Anon;
+	let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();
+	assert!(max > 3, "pre-condition: This test only makes sense for MaxScheduledPerBlock > 3");
+
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+		let mut addrs = Vec::<_>::default();
+
+		// Schedule the maximal number allowed per block.
+		for _ in 0..max {
+			addrs.push(
+				<Scheduler as Anon<_, _, _>>::schedule(
+					DispatchTime::At(4),
+					None,
+					127,
+					root(),
+					bound.clone(),
+				)
+				.unwrap(),
+			);
+		}
+		let mut new_addrs = Vec::<_>::default();
+		// Reversed last three elements of block 4.
+		let last_three = addrs.into_iter().rev().take(3).collect::<Vec<_>>();
+		// Re-schedule three of them to block 5.
+		for addr in last_three.iter().cloned() {
+			new_addrs
+				.push(<Scheduler as Anon<_, _, _>>::reschedule(addr, DispatchTime::At(5)).unwrap());
+		}
+		// Re-scheduling them back into block 3 should result in the same addrs.
+		for (old, want) in new_addrs.into_iter().zip(last_three.into_iter().rev()) {
+			let new = <Scheduler as Anon<_, _, _>>::reschedule(old, DispatchTime::At(4)).unwrap();
+			assert_eq!(new, want);
+		}
+
+		run_to_block(4);
+		// Maximum number of calls are executed.
+		assert_eq!(logger::log().len() as u32, max);
+	});
+}
+
+/// Re-scheduling into the same block produces a different address
+/// if there is still space in the agenda.
+#[test]
+fn scheduler_v3_anon_reschedule_does_not_resuse_addr_if_agenda_not_full() {
+	use frame_support::traits::schedule::v3::Anon;
+	let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();
+	assert!(max > 1, "This test only makes sense for MaxScheduledPerBlock > 1");
+
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+
+		// Schedule both calls.
+		let addr_1 = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call.clone()).unwrap(),
+		)
+		.unwrap();
+		// Cancel the call.
+		assert_ok!(<Scheduler as Anon<_, _, _>>::cancel(addr_1));
+		let addr_2 = <Scheduler as Anon<_, _, _>>::schedule(
+			DispatchTime::At(5),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+		// Re-schedule `call` to block 4.
+		let addr_3 = <Scheduler as Anon<_, _, _>>::reschedule(addr_2, DispatchTime::At(4)).unwrap();
+
+		// Should not re-use the address.
+		assert!(addr_1 != addr_3);
+	});
+}
+
+/// The scheduler can be used as `v3::Named` trait.
+#[test]
+fn scheduler_v3_named_basic_works() {
+	use frame_support::traits::schedule::v3::Named;
+
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let name = [1u8; 32];
+
+		// Schedule a call.
+		let _address = <Scheduler as Named<_, _, _>>::schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+		// Executes in block 4.
+		run_to_block(4);
+		assert_eq!(logger::log(), vec![(root(), 42u32)]);
+		// ... but not again.
+		run_to_block(100);
+		assert_eq!(logger::log(), vec![(root(), 42u32)]);
+	});
+}
+
+/// A named task can be cancelled by its name.
+#[test]
+fn scheduler_v3_named_cancel_named_works() {
+	use frame_support::traits::schedule::v3::Named;
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+		let name = [1u8; 32];
+
+		// Schedule a call.
+		<Scheduler as Named<_, _, _>>::schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+		// Cancel the call by name.
+		assert_ok!(<Scheduler as Named<_, _, _>>::cancel_named(name));
+		// It did not get executed.
+		run_to_block(100);
+		assert!(logger::log().is_empty());
+		// Cannot cancel again.
+		assert_noop!(<Scheduler as Named<_, _, _>>::cancel_named(name), DispatchError::Unavailable);
+	});
+}
+
+/// A named task can also be cancelled by its address.
+#[test]
+fn scheduler_v3_named_cancel_without_name_works() {
+	use frame_support::traits::schedule::v3::{Anon, Named};
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+		let name = [1u8; 32];
+
+		// Schedule a call.
+		let address = <Scheduler as Named<_, _, _>>::schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+		// Cancel the call by address.
+		assert_ok!(<Scheduler as Anon<_, _, _>>::cancel(address));
+		// It did not get executed.
+		run_to_block(100);
+		assert!(logger::log().is_empty());
+		// Cannot cancel again.
+		assert_err!(<Scheduler as Anon<_, _, _>>::cancel(address), DispatchError::Unavailable);
+	});
+}
+
+/// A named task can be re-scheduled by its name but not by its address.
+#[test]
+fn scheduler_v3_named_reschedule_named_works() {
+	use frame_support::traits::schedule::v3::{Anon, Named};
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let name = [1u8; 32];
+
+		// Schedule a call.
+		let address = <Scheduler as Named<_, _, _>>::schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			Preimage::bound(call).unwrap(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+
+		// Cannot re-schedule by address.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(10)),
+			Error::<Test>::Named,
+		);
+		// Cannot re-schedule into the same block.
+		assert_noop!(
+			<Scheduler as Named<_, _, _>>::reschedule_named(name, DispatchTime::At(4)),
+			Error::<Test>::RescheduleNoChange
+		);
+		// Cannot re-schedule into the past.
+		assert_noop!(
+			<Scheduler as Named<_, _, _>>::reschedule_named(name, DispatchTime::At(3)),
+			Error::<Test>::TargetBlockNumberInPast
+		);
+		// Re-schedule to block 5.
+		assert_ok!(<Scheduler as Named<_, _, _>>::reschedule_named(name, DispatchTime::At(5)));
+		// Scheduled for block 5.
+		run_to_block(4);
+		assert!(logger::log().is_empty());
+		run_to_block(5);
+		// Does execute in block 5.
+		assert_eq!(logger::log(), vec![(root(), 42)]);
+		// Cannot re-schedule executed task.
+		assert_noop!(
+			<Scheduler as Named<_, _, _>>::reschedule_named(name, DispatchTime::At(10)),
+			DispatchError::Unavailable
+		);
+		// Also not by address.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::reschedule(address, DispatchTime::At(10)),
+			DispatchError::Unavailable
+		);
+	});
+}
+
+#[test]
+fn scheduler_v3_named_next_schedule_time_works() {
+	use frame_support::traits::schedule::v3::{Anon, Named};
+	new_test_ext().execute_with(|| {
+		let call =
+			RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });
+		let bound = Preimage::bound(call).unwrap();
+		let name = [1u8; 32];
+
+		// Schedule a call.
+		let address = <Scheduler as Named<_, _, _>>::schedule_named(
+			name,
+			DispatchTime::At(4),
+			None,
+			127,
+			root(),
+			bound.clone(),
+		)
+		.unwrap();
+
+		run_to_block(3);
+		// Did not execute till block 3.
+		assert!(logger::log().is_empty());
+
+		// Scheduled for block 4.
+		assert_eq!(<Scheduler as Named<_, _, _>>::next_dispatch_time(name), Ok(4));
+		// Also works by address.
+		assert_eq!(<Scheduler as Anon<_, _, _>>::next_dispatch_time(address), Ok(4));
+		// Block 4 executes it.
+		run_to_block(4);
+		assert_eq!(logger::log(), vec![(root(), 42)]);
+
+		// It has no dispatch time anymore.
+		assert_noop!(
+			<Scheduler as Named<_, _, _>>::next_dispatch_time(name),
+			DispatchError::Unavailable
+		);
+		// Also not by address.
+		assert_noop!(
+			<Scheduler as Anon<_, _, _>>::next_dispatch_time(address),
+			DispatchError::Unavailable
+		);
+	});
+}
diff --git a/substrate/frame/scheduler/src/weights.rs b/substrate/frame/scheduler/src/weights.rs
index afbcf9373b2deb5bd28d1a5f39ea8dabaf9f4236..cb72fe3e2fdda29db5b261bd99dc7ea030275846 100644
--- a/substrate/frame/scheduler/src/weights.rs
+++ b/substrate/frame/scheduler/src/weights.rs
@@ -18,22 +18,24 @@
 //! Autogenerated weights for pallet_scheduler
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/substrate
+// /home/benchbot/cargo_target_dir/production/substrate
 // benchmark
 // pallet
-// --chain=dev
 // --steps=50
 // --repeat=20
-// --pallet=pallet_scheduler
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
-// --template=./.maintain/frame-weight-template.hbs
+// --heap-pages=4096
+// --pallet=pallet_scheduler
+// --chain=dev
 // --output=./frame/scheduler/src/weights.rs
+// --template=./.maintain/frame-weight-template.hbs
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -44,16 +46,14 @@ use sp_std::marker::PhantomData;
 
 /// Weight functions needed for pallet_scheduler.
 pub trait WeightInfo {
-	fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight;
-	fn on_initialize_named_resolved(s: u32, ) -> Weight;
-	fn on_initialize_periodic_resolved(s: u32, ) -> Weight;
-	fn on_initialize_resolved(s: u32, ) -> Weight;
-	fn on_initialize_named_aborted(s: u32, ) -> Weight;
-	fn on_initialize_aborted(s: u32, ) -> Weight;
-	fn on_initialize_periodic_named(s: u32, ) -> Weight;
-	fn on_initialize_periodic(s: u32, ) -> Weight;
-	fn on_initialize_named(s: u32, ) -> Weight;
-	fn on_initialize(s: u32, ) -> Weight;
+	fn service_agendas_base() -> Weight;
+	fn service_agenda_base(s: u32, ) -> Weight;
+	fn service_task_base() -> Weight;
+	fn service_task_fetched(s: u32, ) -> Weight;
+	fn service_task_named() -> Weight;
+	fn service_task_periodic() -> Weight;
+	fn execute_dispatch_signed() -> Weight;
+	fn execute_dispatch_unsigned() -> Weight;
 	fn schedule(s: u32, ) -> Weight;
 	fn cancel(s: u32, ) -> Weight;
 	fn schedule_named(s: u32, ) -> Weight;
@@ -63,149 +63,84 @@ pub trait WeightInfo {
 /// Weights for pallet_scheduler using the Substrate node and recommended hardware.
 pub struct SubstrateWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(9_994_000 as u64)
-			// Standard Error: 20_000
-			.saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64))
+	// Storage: Scheduler IncompleteSince (r:1 w:1)
+	fn service_agendas_base() -> Weight {
+		Weight::from_ref_time(4_992_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(s as u64)))
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(10_318_000 as u64)
-			// Standard Error: 17_000
-			.saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64))
+	/// The range of component `s` is `[0, 512]`.
+	fn service_agenda_base(s: u32, ) -> Weight {
+		Weight::from_ref_time(4_320_000 as u64)
+			// Standard Error: 619
+			.saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(11_675_000 as u64)
-			// Standard Error: 17_000
-			.saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
+	fn service_task_base() -> Weight {
+		Weight::from_ref_time(10_864_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:1 w:1)
 	// Storage: Preimage StatusFor (r:1 w:1)
-	fn on_initialize_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(11_934_000 as u64)
-			// Standard Error: 11_000
-			.saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
-	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:0)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named_aborted(s: u32, ) -> Weight {
-		Weight::from_ref_time(7_279_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(2 as u64))
-			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
-			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
-	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:0)
-	fn on_initialize_aborted(s: u32, ) -> Weight {
-		Weight::from_ref_time(8_619_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64))
+	/// The range of component `s` is `[128, 4194304]`.
+	fn service_task_fetched(s: u32, ) -> Weight {
+		Weight::from_ref_time(24_586_000 as u64)
+			// Standard Error: 1
+			.saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
-			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
 	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_periodic_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(16_129_000 as u64)
-			// Standard Error: 7_000
-			.saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
+	fn service_task_named() -> Weight {
+		Weight::from_ref_time(13_127_000 as u64)
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	fn on_initialize_periodic(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_785_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+	fn service_task_periodic() -> Weight {
+		Weight::from_ref_time(11_053_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_778_000 as u64)
-			// Standard Error: 3_000
-			.saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+	fn execute_dispatch_signed() -> Weight {
+		Weight::from_ref_time(4_158_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
-	fn on_initialize(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_912_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64))
-			.saturating_add(T::DbWeight::get().reads(1 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
+	fn execute_dispatch_unsigned() -> Weight {
+		Weight::from_ref_time(4_104_000 as u64)
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[0, 511]`.
 	fn schedule(s: u32, ) -> Weight {
-		Weight::from_ref_time(18_013_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(20_074_000 as u64)
+			// Standard Error: 765
+			.saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
 	// Storage: Scheduler Lookup (r:0 w:1)
+	/// The range of component `s` is `[1, 512]`.
 	fn cancel(s: u32, ) -> Weight {
-		Weight::from_ref_time(18_131_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(21_509_000 as u64)
+			// Standard Error: 708
+			.saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(1 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Scheduler Lookup (r:1 w:1)
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[0, 511]`.
 	fn schedule_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(21_230_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(22_427_000 as u64)
+			// Standard Error: 850
+			.saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	// Storage: Scheduler Lookup (r:1 w:1)
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[1, 512]`.
 	fn cancel_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(20_139_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(22_875_000 as u64)
+			// Standard Error: 693
+			.saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
@@ -213,149 +148,84 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 
 // For backwards compatibility and tests
 impl WeightInfo for () {
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(9_994_000 as u64)
-			// Standard Error: 20_000
-			.saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64))
+	// Storage: Scheduler IncompleteSince (r:1 w:1)
+	fn service_agendas_base() -> Weight {
+		Weight::from_ref_time(4_992_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(s as u64)))
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(10_318_000 as u64)
-			// Standard Error: 17_000
-			.saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64))
+	/// The range of component `s` is `[0, 512]`.
+	fn service_agenda_base(s: u32, ) -> Weight {
+		Weight::from_ref_time(4_320_000 as u64)
+			// Standard Error: 619
+			.saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:1)
-	// Storage: Preimage StatusFor (r:1 w:1)
-	fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(11_675_000 as u64)
-			// Standard Error: 17_000
-			.saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64)))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64)))
+	fn service_task_base() -> Weight {
+		Weight::from_ref_time(10_864_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
 	// Storage: Preimage PreimageFor (r:1 w:1)
 	// Storage: Preimage StatusFor (r:1 w:1)
-	fn on_initialize_resolved(s: u32, ) -> Weight {
-		Weight::from_ref_time(11_934_000 as u64)
-			// Standard Error: 11_000
-			.saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64)))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
-	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:0)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named_aborted(s: u32, ) -> Weight {
-		Weight::from_ref_time(7_279_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(2 as u64))
-			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
-			.saturating_add(RocksDbWeight::get().writes(2 as u64))
-			.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
-	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	// Storage: Preimage PreimageFor (r:1 w:0)
-	fn on_initialize_aborted(s: u32, ) -> Weight {
-		Weight::from_ref_time(8_619_000 as u64)
-			// Standard Error: 4_000
-			.saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64))
+	/// The range of component `s` is `[128, 4194304]`.
+	fn service_task_fetched(s: u32, ) -> Weight {
+		Weight::from_ref_time(24_586_000 as u64)
+			// Standard Error: 1
+			.saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
-			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
 	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_periodic_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(16_129_000 as u64)
-			// Standard Error: 7_000
-			.saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
+	fn service_task_named() -> Weight {
+		Weight::from_ref_time(13_127_000 as u64)
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64)))
 	}
-	// Storage: Scheduler Agenda (r:2 w:2)
-	fn on_initialize_periodic(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_785_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64)))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+	fn service_task_periodic() -> Weight {
+		Weight::from_ref_time(11_053_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
-	// Storage: Scheduler Lookup (r:0 w:1)
-	fn on_initialize_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_778_000 as u64)
-			// Standard Error: 3_000
-			.saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64)))
+	fn execute_dispatch_signed() -> Weight {
+		Weight::from_ref_time(4_158_000 as u64)
 	}
-	// Storage: Scheduler Agenda (r:1 w:1)
-	fn on_initialize(s: u32, ) -> Weight {
-		Weight::from_ref_time(15_912_000 as u64)
-			// Standard Error: 5_000
-			.saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64))
-			.saturating_add(RocksDbWeight::get().reads(1 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
+	fn execute_dispatch_unsigned() -> Weight {
+		Weight::from_ref_time(4_104_000 as u64)
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[0, 511]`.
 	fn schedule(s: u32, ) -> Weight {
-		Weight::from_ref_time(18_013_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(20_074_000 as u64)
+			// Standard Error: 765
+			.saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	// Storage: Scheduler Agenda (r:1 w:1)
 	// Storage: Scheduler Lookup (r:0 w:1)
+	/// The range of component `s` is `[1, 512]`.
 	fn cancel(s: u32, ) -> Weight {
-		Weight::from_ref_time(18_131_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(21_509_000 as u64)
+			// Standard Error: 708
+			.saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(1 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Scheduler Lookup (r:1 w:1)
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[0, 511]`.
 	fn schedule_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(21_230_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(22_427_000 as u64)
+			// Standard Error: 850
+			.saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	// Storage: Scheduler Lookup (r:1 w:1)
 	// Storage: Scheduler Agenda (r:1 w:1)
+	/// The range of component `s` is `[1, 512]`.
 	fn cancel_named(s: u32, ) -> Weight {
-		Weight::from_ref_time(20_139_000 as u64)
-			// Standard Error: 1_000
-			.saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64))
+		Weight::from_ref_time(22_875_000 as u64)
+			// Standard Error: 693
+			.saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
index acbcb65a3e986add41cd080a8785a2b0b99e5f95..1551d85ea4c96fac8fae8d38280610929e85d3a1 100644
--- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
+++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs
@@ -169,6 +169,10 @@ pub fn expand_outer_origin(
 				&self.caller
 			}
 
+			fn into_caller(self) -> Self::PalletsOrigin {
+				self.caller
+			}
+
 			fn try_with_caller<R>(
 				mut self,
 				f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -190,13 +194,6 @@ pub fn expand_outer_origin(
 			fn signed(by: Self::AccountId) -> Self {
 				#system_path::RawOrigin::Signed(by).into()
 			}
-
-			fn as_signed(self) -> Option<Self::AccountId> {
-				match self.caller {
-					OriginCaller::system(#system_path::RawOrigin::Signed(by)) => Some(by),
-					_ => None,
-				}
-			}
 		}
 
 		#[derive(
@@ -215,7 +212,6 @@ pub fn expand_outer_origin(
 		// For backwards compatibility and ease of accessing these functions.
 		#[allow(dead_code)]
 		impl RuntimeOrigin {
-
 			#[doc = #doc_string_none_origin]
 			pub fn none() -> Self {
 				<RuntimeOrigin as #scrate::traits::OriginTrait>::none()
@@ -238,6 +234,21 @@ pub fn expand_outer_origin(
 			}
 		}
 
+		impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller {
+			fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
+				match self {
+					OriginCaller::system(x) => Some(x),
+					_ => None,
+				}
+			}
+			fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
+				match &self {
+					OriginCaller::system(o) => Some(o),
+					_ => None,
+				}
+			}
+		}
+
 		impl TryFrom<OriginCaller> for #system_path::Origin<#runtime> {
 			type Error = OriginCaller;
 			fn try_from(x: OriginCaller)
diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs
index db2bc90658ee2e4b02994c42b08729e1cce77ff1..d497a672e2970c6fa0e01452d4a5553df46bbdfe 100644
--- a/substrate/frame/support/src/dispatch.rs
+++ b/substrate/frame/support/src/dispatch.rs
@@ -3181,8 +3181,8 @@ mod tests {
 		dispatch::{DispatchClass, DispatchInfo, Pays},
 		metadata::*,
 		traits::{
-			CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize,
-			OnRuntimeUpgrade, PalletInfo,
+			CallerTrait, CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle,
+			OnInitialize, OnRuntimeUpgrade, PalletInfo,
 		},
 	};
 	use sp_weights::RuntimeDbWeight;
@@ -3300,6 +3300,16 @@ mod tests {
 		}
 	}
 
+	impl CallerTrait<<TraitImpl as system::Config>::AccountId> for OuterOrigin {
+		fn into_system(self) -> Option<RawOrigin<<TraitImpl as system::Config>::AccountId>> {
+			unimplemented!("Not required in tests!")
+		}
+
+		fn as_system_ref(&self) -> Option<&RawOrigin<<TraitImpl as system::Config>::AccountId>> {
+			unimplemented!("Not required in tests!")
+		}
+	}
+
 	impl crate::traits::OriginTrait for OuterOrigin {
 		type Call = <TraitImpl as system::Config>::RuntimeCall;
 		type PalletsOrigin = OuterOrigin;
@@ -3325,6 +3335,10 @@ mod tests {
 			unimplemented!("Not required in tests!")
 		}
 
+		fn into_caller(self) -> Self::PalletsOrigin {
+			unimplemented!("Not required in tests!")
+		}
+
 		fn try_with_caller<R>(
 			self,
 			_f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -3344,6 +3358,9 @@ mod tests {
 		fn as_signed(self) -> Option<Self::AccountId> {
 			unimplemented!("Not required in tests!")
 		}
+		fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
+			unimplemented!("Not required in tests!")
+		}
 	}
 
 	impl system::Config for TraitImpl {
diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs
index d51c32649a797c52debd1ffa908e658243e4349d..302d3354dae5e1b2278fda6485b095b5a9f4ccc4 100644
--- a/substrate/frame/support/src/traits.rs
+++ b/substrate/frame/support/src/traits.rs
@@ -58,10 +58,11 @@ pub use misc::{
 	Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16,
 	ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly,
 	EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime,
-	IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider,
-	PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime,
-	WrapperKeepOpaque, WrapperOpaque,
+	IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp,
+	SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque,
 };
+#[allow(deprecated)]
+pub use misc::{PreimageProvider, PreimageRecipient};
 #[doc(hidden)]
 pub use misc::{DEFENSIVE_OP_INTERNAL_ERROR, DEFENSIVE_OP_PUBLIC_ERROR};
 
@@ -96,8 +97,9 @@ mod dispatch;
 #[allow(deprecated)]
 pub use dispatch::EnsureOneOf;
 pub use dispatch::{
-	AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg,
-	MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable,
+	AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin,
+	EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess,
+	UnfilteredDispatchable,
 };
 
 mod voting;
@@ -106,6 +108,9 @@ pub use voting::{
 	U128CurrencyToVote, VoteTally,
 };
 
+mod preimages;
+pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage};
+
 #[cfg(feature = "try-runtime")]
 mod try_runtime;
 #[cfg(feature = "try-runtime")]
diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs
index c0e7e32a5529e9d825cdb31c0b665ad5f1d7d440..b96cfae4500e23c5c731afc151dc64d07687ceee 100644
--- a/substrate/frame/support/src/traits/dispatch.rs
+++ b/substrate/frame/support/src/traits/dispatch.rs
@@ -236,17 +236,25 @@ pub trait UnfilteredDispatchable {
 	fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo;
 }
 
+/// The trait implemented by the overarching enumeration of the different pallets' origins.
+/// Unlike `OriginTrait` impls, this does not include any kind of dispatch/call filter. Also, this
+/// trait is more flexible in terms of how it can be used: it is a `Parameter` and `Member`, so it
+/// can be used as dispatchable parameters as well as in storage items.
+pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>> {
+	/// Extract the signer from the message if it is a `Signed` origin.
+	fn into_system(self) -> Option<RawOrigin<AccountId>>;
+
+	/// Extract a reference to the system-level `RawOrigin` if it is that.
+	fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
+}
+
 /// Methods available on `frame_system::Config::RuntimeOrigin`.
 pub trait OriginTrait: Sized {
 	/// Runtime call type, as in `frame_system::Config::Call`
 	type Call;
 
 	/// The caller origin, overarching type of all pallets origins.
-	type PalletsOrigin: Parameter
-		+ Member
-		+ Into<Self>
-		+ From<RawOrigin<Self::AccountId>>
-		+ MaxEncodedLen;
+	type PalletsOrigin: Into<Self> + CallerTrait<Self::AccountId> + MaxEncodedLen;
 
 	/// The AccountId used across the system.
 	type AccountId;
@@ -266,9 +274,12 @@ pub trait OriginTrait: Sized {
 	/// For root origin caller, the filters are bypassed and true is returned.
 	fn filter_call(&self, call: &Self::Call) -> bool;
 
-	/// Get the caller.
+	/// Get a reference to the caller (`CallerTrait` impl).
 	fn caller(&self) -> &Self::PalletsOrigin;
 
+	/// Consume `self` and return the caller.
+	fn into_caller(self) -> Self::PalletsOrigin;
+
 	/// Do something with the caller, consuming self but returning it if the caller was unused.
 	fn try_with_caller<R>(
 		self,
@@ -285,7 +296,20 @@ pub trait OriginTrait: Sized {
 	fn signed(by: Self::AccountId) -> Self;
 
 	/// Extract the signer from the message if it is a `Signed` origin.
-	fn as_signed(self) -> Option<Self::AccountId>;
+	fn as_signed(self) -> Option<Self::AccountId> {
+		self.into_caller().into_system().and_then(|s| {
+			if let RawOrigin::Signed(who) = s {
+				Some(who)
+			} else {
+				None
+			}
+		})
+	}
+
+	/// Extract a reference to the sytsem origin, if that's what the caller is.
+	fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
+		self.caller().as_system_ref()
+	}
 }
 
 #[cfg(test)]
diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs
index 7fc4a6fb08a5ac914a8b5c7b69e0a86266c43357..5a976478fa7c4769a62861383091dadf172e6957 100644
--- a/substrate/frame/support/src/traits/misc.rs
+++ b/substrate/frame/support/src/traits/misc.rs
@@ -932,7 +932,7 @@ pub trait PreimageRecipient<Hash>: PreimageProvider<Hash> {
 	/// Maximum size of a preimage.
 	type MaxSize: Get<u32>;
 
-	/// Store the bytes of a preimage on chain.
+	/// Store the bytes of a preimage on chain infallible due to the bounded type.
 	fn note_preimage(bytes: crate::BoundedVec<u8, Self::MaxSize>);
 
 	/// Clear a previously noted preimage. This is infallible and should be treated more like a
diff --git a/substrate/frame/support/src/traits/preimages.rs b/substrate/frame/support/src/traits/preimages.rs
new file mode 100644
index 0000000000000000000000000000000000000000..594532ba969036ffc04b4b6bf8be18bc4b2f3f4e
--- /dev/null
+++ b/substrate/frame/support/src/traits/preimages.rs
@@ -0,0 +1,317 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Stuff for dealing with 32-byte hashed preimages.
+
+use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
+use sp_core::{RuntimeDebug, H256};
+use sp_io::hashing::blake2_256;
+use sp_runtime::{traits::ConstU32, DispatchError};
+use sp_std::borrow::Cow;
+
+pub type Hash = H256;
+pub type BoundedInline = crate::BoundedVec<u8, ConstU32<128>>;
+
+#[derive(
+	Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug,
+)]
+#[codec(mel_bound())]
+pub enum Bounded<T> {
+	/// A Blake2 256 hash with no preimage length. We
+	/// do not support creation of this except for transitioning from legacy state.
+	/// In the future we will make this a pure `Dummy` item storing only the final `dummy` field.
+	Legacy { hash: Hash, dummy: sp_std::marker::PhantomData<T> },
+	/// A an bounded `Call`. Its encoding must be at most 128 bytes.
+	Inline(BoundedInline),
+	/// A Blake2-256 hash of the call together with an upper limit for its size.
+	Lookup { hash: Hash, len: u32 },
+}
+
+impl<T> Bounded<T> {
+	/// Casts the wrapped type into something that encodes alike.
+	///
+	/// # Examples
+	/// ```
+	/// use frame_support::traits::Bounded;
+	///
+	/// // Transmute from `String` to `&str`.
+	/// let x: Bounded<String> = Bounded::Inline(Default::default());
+	/// let _: Bounded<&str> = x.transmute();
+	/// ```
+	pub fn transmute<S: Encode>(self) -> Bounded<S>
+	where
+		T: Encode + EncodeLike<S>,
+	{
+		use Bounded::*;
+		match self {
+			Legacy { hash, .. } => Legacy { hash, dummy: sp_std::marker::PhantomData },
+			Inline(x) => Inline(x),
+			Lookup { hash, len } => Lookup { hash, len },
+		}
+	}
+
+	/// Returns the hash of the preimage.
+	///
+	/// The hash is re-calculated every time if the preimage is inlined.
+	pub fn hash(&self) -> H256 {
+		use Bounded::*;
+		match self {
+			Legacy { hash, .. } => *hash,
+			Inline(x) => blake2_256(x.as_ref()).into(),
+			Lookup { hash, .. } => *hash,
+		}
+	}
+}
+
+// The maximum we expect a single legacy hash lookup to be.
+const MAX_LEGACY_LEN: u32 = 1_000_000;
+
+impl<T> Bounded<T> {
+	/// Returns the length of the preimage or `None` if the length is unknown.
+	pub fn len(&self) -> Option<u32> {
+		match self {
+			Self::Legacy { .. } => None,
+			Self::Inline(i) => Some(i.len() as u32),
+			Self::Lookup { len, .. } => Some(*len),
+		}
+	}
+
+	/// Returns whether the image will require a lookup to be peeked.
+	pub fn lookup_needed(&self) -> bool {
+		match self {
+			Self::Inline(..) => false,
+			Self::Legacy { .. } | Self::Lookup { .. } => true,
+		}
+	}
+
+	/// The maximum length of the lookup that is needed to peek `Self`.
+	pub fn lookup_len(&self) -> Option<u32> {
+		match self {
+			Self::Inline(..) => None,
+			Self::Legacy { .. } => Some(MAX_LEGACY_LEN),
+			Self::Lookup { len, .. } => Some(*len),
+		}
+	}
+
+	/// Constructs a `Lookup` bounded item.
+	pub fn unrequested(hash: Hash, len: u32) -> Self {
+		Self::Lookup { hash, len }
+	}
+
+	/// Constructs a `Legacy` bounded item.
+	#[deprecated = "This API is only for transitioning to Scheduler v3 API"]
+	pub fn from_legacy_hash(hash: impl Into<Hash>) -> Self {
+		Self::Legacy { hash: hash.into(), dummy: sp_std::marker::PhantomData }
+	}
+}
+
+pub type FetchResult = Result<Cow<'static, [u8]>, DispatchError>;
+
+/// A interface for looking up preimages from their hash on chain.
+pub trait QueryPreimage {
+	/// Returns whether a preimage exists for a given hash and if so its length.
+	fn len(hash: &Hash) -> Option<u32>;
+
+	/// Returns the preimage for a given hash. If given, `len` must be the size of the preimage.
+	fn fetch(hash: &Hash, len: Option<u32>) -> FetchResult;
+
+	/// Returns whether a preimage request exists for a given hash.
+	fn is_requested(hash: &Hash) -> bool;
+
+	/// Request that someone report a preimage. Providers use this to optimise the economics for
+	/// preimage reporting.
+	fn request(hash: &Hash);
+
+	/// Cancel a previous preimage request.
+	fn unrequest(hash: &Hash);
+
+	/// Request that the data required for decoding the given `bounded` value is made available.
+	fn hold<T>(bounded: &Bounded<T>) {
+		use Bounded::*;
+		match bounded {
+			Inline(..) => {},
+			Legacy { hash, .. } | Lookup { hash, .. } => Self::request(hash),
+		}
+	}
+
+	/// No longer request that the data required for decoding the given `bounded` value is made
+	/// available.
+	fn drop<T>(bounded: &Bounded<T>) {
+		use Bounded::*;
+		match bounded {
+			Inline(..) => {},
+			Legacy { hash, .. } | Lookup { hash, .. } => Self::unrequest(hash),
+		}
+	}
+
+	/// Check to see if all data required for the given `bounded` value is available for its
+	/// decoding.
+	fn have<T>(bounded: &Bounded<T>) -> bool {
+		use Bounded::*;
+		match bounded {
+			Inline(..) => true,
+			Legacy { hash, .. } | Lookup { hash, .. } => Self::len(hash).is_some(),
+		}
+	}
+
+	/// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not
+	/// be `peek`-able or `realize`-able.
+	fn pick<T>(hash: Hash, len: u32) -> Bounded<T> {
+		Self::request(&hash);
+		Bounded::Lookup { hash, len }
+	}
+
+	/// Convert the given `bounded` instance back into its original instance, also returning the
+	/// exact size of its encoded form if it needed to be looked-up from a stored preimage).
+	///
+	/// NOTE: This does not remove any data needed for realization. If you will no longer use the
+	/// `bounded`, call `realize` instead or call `drop` afterwards.
+	fn peek<T: Decode>(bounded: &Bounded<T>) -> Result<(T, Option<u32>), DispatchError> {
+		use Bounded::*;
+		match bounded {
+			Inline(data) => T::decode(&mut &data[..]).ok().map(|x| (x, None)),
+			Lookup { hash, len } => {
+				let data = Self::fetch(hash, Some(*len))?;
+				T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32)))
+			},
+			Legacy { hash, .. } => {
+				let data = Self::fetch(hash, None)?;
+				T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32)))
+			},
+		}
+		.ok_or(DispatchError::Corruption)
+	}
+
+	/// Convert the given `bounded` value back into its original instance. If successful,
+	/// `drop` any data backing it. This will not break the realisability of independently
+	/// created instances of `Bounded` which happen to have identical data.
+	fn realize<T: Decode>(bounded: &Bounded<T>) -> Result<(T, Option<u32>), DispatchError> {
+		let r = Self::peek(bounded)?;
+		Self::drop(bounded);
+		Ok(r)
+	}
+}
+
+/// A interface for managing preimages to hashes on chain.
+///
+/// Note that this API does not assume any underlying user is calling, and thus
+/// does not handle any preimage ownership or fees. Other system level logic that
+/// uses this API should implement that on their own side.
+pub trait StorePreimage: QueryPreimage {
+	/// The maximum length of preimage we can store.
+	///
+	/// This is the maximum length of the *encoded* value that can be passed to `bound`.
+	const MAX_LENGTH: usize;
+
+	/// Request and attempt to store the bytes of a preimage on chain.
+	///
+	/// May return `DispatchError::Exhausted` if the preimage is just too big.
+	fn note(bytes: Cow<[u8]>) -> Result<Hash, DispatchError>;
+
+	/// Attempt to clear a previously noted preimage. Exactly the same as `unrequest` but is
+	/// provided for symmetry.
+	fn unnote(hash: &Hash) {
+		Self::unrequest(hash)
+	}
+
+	/// Convert an otherwise unbounded or large value into a type ready for placing in storage. The
+	/// result is a type whose `MaxEncodedLen` is 131 bytes.
+	///
+	/// NOTE: Once this API is used, you should use either `drop` or `realize`.
+	fn bound<T: Encode>(t: T) -> Result<Bounded<T>, DispatchError> {
+		let data = t.encode();
+		let len = data.len() as u32;
+		Ok(match BoundedInline::try_from(data) {
+			Ok(bounded) => Bounded::Inline(bounded),
+			Err(unbounded) => Bounded::Lookup { hash: Self::note(unbounded.into())?, len },
+		})
+	}
+}
+
+impl QueryPreimage for () {
+	fn len(_: &Hash) -> Option<u32> {
+		None
+	}
+	fn fetch(_: &Hash, _: Option<u32>) -> FetchResult {
+		Err(DispatchError::Unavailable)
+	}
+	fn is_requested(_: &Hash) -> bool {
+		false
+	}
+	fn request(_: &Hash) {}
+	fn unrequest(_: &Hash) {}
+}
+
+impl StorePreimage for () {
+	const MAX_LENGTH: usize = 0;
+	fn note(_: Cow<[u8]>) -> Result<Hash, DispatchError> {
+		Err(DispatchError::Exhausted)
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use crate::{bounded_vec, BoundedVec};
+
+	#[test]
+	fn bounded_size_is_correct() {
+		assert_eq!(<Bounded<Vec<u8>> as MaxEncodedLen>::max_encoded_len(), 131);
+	}
+
+	#[test]
+	fn bounded_basic_works() {
+		let data: BoundedVec<u8, _> = bounded_vec![b'a', b'b', b'c'];
+		let len = data.len() as u32;
+		let hash = blake2_256(&data).into();
+
+		// Inline works
+		{
+			let bound: Bounded<Vec<u8>> = Bounded::Inline(data.clone());
+			assert_eq!(bound.hash(), hash);
+			assert_eq!(bound.len(), Some(len));
+			assert!(!bound.lookup_needed());
+			assert_eq!(bound.lookup_len(), None);
+		}
+		// Legacy works
+		{
+			let bound: Bounded<Vec<u8>> = Bounded::Legacy { hash, dummy: Default::default() };
+			assert_eq!(bound.hash(), hash);
+			assert_eq!(bound.len(), None);
+			assert!(bound.lookup_needed());
+			assert_eq!(bound.lookup_len(), Some(1_000_000));
+		}
+		// Lookup works
+		{
+			let bound: Bounded<Vec<u8>> = Bounded::Lookup { hash, len: data.len() as u32 };
+			assert_eq!(bound.hash(), hash);
+			assert_eq!(bound.len(), Some(len));
+			assert!(bound.lookup_needed());
+			assert_eq!(bound.lookup_len(), Some(len));
+		}
+	}
+
+	#[test]
+	fn bounded_transmuting_works() {
+		let data: BoundedVec<u8, _> = bounded_vec![b'a', b'b', b'c'];
+
+		// Transmute a `String` into a `&str`.
+		let x: Bounded<String> = Bounded::Inline(data.clone());
+		let y: Bounded<&str> = x.transmute();
+		assert_eq!(y, Bounded::Inline(data));
+	}
+}
diff --git a/substrate/frame/support/src/traits/schedule.rs b/substrate/frame/support/src/traits/schedule.rs
index 0dbbbd9e2a553e67dbbb08025aec2017efaf62ca..b8e6a7f80790436f2b7a4380533d46dbafe38a70 100644
--- a/substrate/frame/support/src/traits/schedule.rs
+++ b/substrate/frame/support/src/traits/schedule.rs
@@ -17,6 +17,8 @@
 
 //! Traits and associated utilities for scheduling dispatchables in FRAME.
 
+#[allow(deprecated)]
+use super::PreimageProvider;
 use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen};
 use scale_info::TypeInfo;
 use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug};
@@ -128,6 +130,7 @@ impl<T: Decode, H> MaybeHashed<T, H> {
 	}
 }
 
+// TODO: deprecate
 pub mod v1 {
 	use super::*;
 
@@ -283,6 +286,7 @@ pub mod v1 {
 	}
 }
 
+// TODO: deprecate
 pub mod v2 {
 	use super::*;
 
@@ -375,6 +379,97 @@ pub mod v2 {
 	}
 }
 
-pub use v1::*;
+pub mod v3 {
+	use super::*;
+	use crate::traits::Bounded;
 
-use super::PreimageProvider;
+	/// A type that can be used as a scheduler.
+	pub trait Anon<BlockNumber, Call, Origin> {
+		/// An address which can be used for removing a scheduled task.
+		type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo;
+
+		/// Schedule a dispatch to happen at the beginning of some block in the future.
+		///
+		/// This is not named.
+		fn schedule(
+			when: DispatchTime<BlockNumber>,
+			maybe_periodic: Option<Period<BlockNumber>>,
+			priority: Priority,
+			origin: Origin,
+			call: Bounded<Call>,
+		) -> Result<Self::Address, DispatchError>;
+
+		/// Cancel a scheduled task. If periodic, then it will cancel all further instances of that,
+		/// also.
+		///
+		/// Will return an `Unavailable` error if the `address` is invalid.
+		///
+		/// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
+		/// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
+		///
+		/// NOTE2: This will not work to cancel periodic tasks after their initial execution. For
+		/// that, you must name the task explicitly using the `Named` trait.
+		fn cancel(address: Self::Address) -> Result<(), DispatchError>;
+
+		/// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
+		/// only if it is executed *before* the currently scheduled block. For periodic tasks,
+		/// this dispatch is guaranteed to succeed only before the *initial* execution; for
+		/// others, use `reschedule_named`.
+		///
+		/// Will return an `Unavailable` error if the `address` is invalid.
+		fn reschedule(
+			address: Self::Address,
+			when: DispatchTime<BlockNumber>,
+		) -> Result<Self::Address, DispatchError>;
+
+		/// Return the next dispatch time for a given task.
+		///
+		/// Will return an `Unavailable` error if the `address` is invalid.
+		fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, DispatchError>;
+	}
+
+	pub type TaskName = [u8; 32];
+
+	/// A type that can be used as a scheduler.
+	pub trait Named<BlockNumber, Call, Origin> {
+		/// An address which can be used for removing a scheduled task.
+		type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + sp_std::fmt::Debug;
+
+		/// Schedule a dispatch to happen at the beginning of some block in the future.
+		///
+		/// - `id`: The identity of the task. This must be unique and will return an error if not.
+		fn schedule_named(
+			id: TaskName,
+			when: DispatchTime<BlockNumber>,
+			maybe_periodic: Option<Period<BlockNumber>>,
+			priority: Priority,
+			origin: Origin,
+			call: Bounded<Call>,
+		) -> Result<Self::Address, DispatchError>;
+
+		/// Cancel a scheduled, named task. If periodic, then it will cancel all further instances
+		/// of that, also.
+		///
+		/// Will return an `Unavailable` error if the `id` is invalid.
+		///
+		/// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
+		/// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
+		fn cancel_named(id: TaskName) -> Result<(), DispatchError>;
+
+		/// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
+		/// only if it is executed *before* the currently scheduled block.
+		///
+		/// Will return an `Unavailable` error if the `id` is invalid.
+		fn reschedule_named(
+			id: TaskName,
+			when: DispatchTime<BlockNumber>,
+		) -> Result<Self::Address, DispatchError>;
+
+		/// Return the next dispatch time for a given task.
+		///
+		/// Will return an `Unavailable` error if the `id` is invalid.
+		fn next_dispatch_time(id: TaskName) -> Result<BlockNumber, DispatchError>;
+	}
+}
+
+pub use v1::*;
diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr
index b0716d569409c07fac1756d98ab1cc6fe69eccab..b8a9a1128d669ea132c44278d92f742127aaaa49 100644
--- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr
+++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr
@@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
              <&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
              <&[(T,)] as EncodeLike<LinkedList<LikeT>>>
              <&[T] as EncodeLike<Vec<U>>>
-           and 279 others
+           and 280 others
    = note: required because of the requirements on the impl of `FullEncode` for `Bar`
    = note: required because of the requirements on the impl of `FullCodec` for `Bar`
    = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied
              (A, B, C, D)
              (A, B, C, D, E)
              (A, B, C, D, E, F)
-           and 160 others
+           and 161 others
    = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar`
    = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
 
@@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
              <&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
              <&[(T,)] as EncodeLike<LinkedList<LikeT>>>
              <&[T] as EncodeLike<Vec<U>>>
-           and 279 others
+           and 280 others
    = note: required because of the requirements on the impl of `FullEncode` for `Bar`
    = note: required because of the requirements on the impl of `FullCodec` for `Bar`
    = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr
index 926dc925306594c495fcd802b76f904a9ceb43fc..5032f63bc1b1b20ad93218e0abd76a0a2c19fe57 100644
--- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr
+++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr
@@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
              <&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
              <&[(T,)] as EncodeLike<LinkedList<LikeT>>>
              <&[T] as EncodeLike<Vec<U>>>
-           and 279 others
+           and 280 others
    = note: required because of the requirements on the impl of `FullEncode` for `Bar`
    = note: required because of the requirements on the impl of `FullCodec` for `Bar`
    = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
@@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied
              (A, B, C, D)
              (A, B, C, D, E)
              (A, B, C, D, E, F)
-           and 160 others
+           and 161 others
    = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar`
    = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
 
@@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied
              <&[(T,)] as EncodeLike<BinaryHeap<LikeT>>>
              <&[(T,)] as EncodeLike<LinkedList<LikeT>>>
              <&[T] as EncodeLike<Vec<U>>>
-           and 279 others
+           and 280 others
    = note: required because of the requirements on the impl of `FullEncode` for `Bar`
    = note: required because of the requirements on the impl of `FullCodec` for `Bar`
    = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr
index 563190a06f76fb395a3b9ecf055deeb5a92d78da..8d3d7a71a313e7a0a1b111449e31a2b117a25ea7 100644
--- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr
+++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr
@@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied
             (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
             (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
             (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
-          and 77 others
+          and 78 others
   = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo<T>, Bar>`
diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr
index c10005223b67439d0c13d997f53934b4cd385af2..ebf24a1232e3c61613f20fa73933b741dd2db634 100644
--- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr
+++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr
@@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied
              (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
              (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
              (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
-           and 77 others
+           and 78 others
    = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key<frame_support::Twox64Concat, Bar>`
    = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, Key<frame_support::Twox64Concat, Bar>, u32>`
diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs
index dc74157da79de56e9c746923524dc19f12ef9f5c..7577d0dc6b158f3b2bd71b546c801e61e65fcb1b 100644
--- a/substrate/frame/system/src/lib.rs
+++ b/substrate/frame/system/src/lib.rs
@@ -222,7 +222,10 @@ pub mod pallet {
 			+ OriginTrait<Call = Self::RuntimeCall>;
 
 		/// The aggregated `RuntimeCall` type.
-		type RuntimeCall: Dispatchable + Debug;
+		type RuntimeCall: Parameter
+			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+			+ Debug
+			+ From<Call<Self>>;
 
 		/// Account index (aka nonce) type. This stores the number of previous transactions
 		/// associated with a sender account.
diff --git a/substrate/frame/whitelist/src/mock.rs b/substrate/frame/whitelist/src/mock.rs
index 44aea86be6f1998ea0de5da0e0240d16d645a5a4..d4446cb8031ab81e29a0d339ccfa1feb1504a66f 100644
--- a/substrate/frame/whitelist/src/mock.rs
+++ b/substrate/frame/whitelist/src/mock.rs
@@ -96,7 +96,6 @@ impl pallet_preimage::Config for Test {
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type ManagerOrigin = EnsureRoot<Self::AccountId>;
-	type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference.
 	type BaseDeposit = ConstU64<1>;
 	type ByteDeposit = ConstU64<1>;
 	type WeightInfo = ();
diff --git a/substrate/primitives/core/src/bounded/bounded_vec.rs b/substrate/primitives/core/src/bounded/bounded_vec.rs
index 85f2bed316793c6135a507e14cfd4836a117fd5f..1832e43e8646c75cee43f2fec1c8dac983ab8180 100644
--- a/substrate/primitives/core/src/bounded/bounded_vec.rs
+++ b/substrate/primitives/core/src/bounded/bounded_vec.rs
@@ -276,6 +276,14 @@ impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> {
 	}
 }
 
+impl<'a, T, S: Get<u32>> BoundedSlice<'a, T, S> {
+	/// Create an instance from the first elements of the given slice (or all of it if it is smaller
+	/// than the length bound).
+	pub fn truncate_from(s: &'a [T]) -> Self {
+		Self(&s[0..(s.len().min(S::get() as usize))], PhantomData)
+	}
+}
+
 impl<T: Decode, S: Get<u32>> Decode for BoundedVec<T, S> {
 	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
 		let inner = Vec::<T>::decode(input)?;
@@ -620,12 +628,12 @@ impl<T, S: Get<u32>> BoundedVec<T, S> {
 	/// # Panics
 	///
 	/// Panics if `index > len`.
-	pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> {
+	pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), T> {
 		if self.len() < Self::bound() {
 			self.0.insert(index, element);
 			Ok(())
 		} else {
-			Err(())
+			Err(element)
 		}
 	}
 
@@ -635,12 +643,12 @@ impl<T, S: Get<u32>> BoundedVec<T, S> {
 	/// # Panics
 	///
 	/// Panics if the new capacity exceeds isize::MAX bytes.
-	pub fn try_push(&mut self, element: T) -> Result<(), ()> {
+	pub fn try_push(&mut self, element: T) -> Result<(), T> {
 		if self.len() < Self::bound() {
 			self.0.push(element);
 			Ok(())
 		} else {
-			Err(())
+			Err(element)
 		}
 	}
 }
@@ -673,13 +681,13 @@ where
 }
 
 impl<T, S: Get<u32>> TryFrom<Vec<T>> for BoundedVec<T, S> {
-	type Error = ();
+	type Error = Vec<T>;
 	fn try_from(t: Vec<T>) -> Result<Self, Self::Error> {
 		if t.len() <= Self::bound() {
 			// explicit check just above
 			Ok(Self::unchecked_from(t))
 		} else {
-			Err(())
+			Err(t)
 		}
 	}
 }
@@ -886,6 +894,16 @@ pub mod test {
 	use super::*;
 	use crate::{bounded_vec, ConstU32};
 
+	#[test]
+	fn slice_truncate_from_works() {
+		let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3, 4, 5]);
+		assert_eq!(bounded.deref(), &[1, 2, 3, 4]);
+		let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3, 4]);
+		assert_eq!(bounded.deref(), &[1, 2, 3, 4]);
+		let bounded = BoundedSlice::<u32, ConstU32<4>>::truncate_from(&[1, 2, 3]);
+		assert_eq!(bounded.deref(), &[1, 2, 3]);
+	}
+
 	#[test]
 	fn slide_works() {
 		let mut b: BoundedVec<u32, ConstU32<6>> = bounded_vec![0, 1, 2, 3, 4, 5];
diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs
index 8017a6ac529a283a9651372dd53b46dffd801915..96706dd91965004d5f7a2f6dcb5db2a28d2bfb5d 100644
--- a/substrate/primitives/runtime/src/lib.rs
+++ b/substrate/primitives/runtime/src/lib.rs
@@ -547,6 +547,12 @@ pub enum DispatchError {
 	/// The number of transactional layers has been reached, or we are not in a transactional
 	/// layer.
 	Transactional(TransactionalError),
+	/// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate.
+	Exhausted,
+	/// The state is corrupt; this is generally not going to fix itself.
+	Corruption,
+	/// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later.
+	Unavailable,
 }
 
 /// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about
@@ -671,18 +677,21 @@ impl From<&'static str> for DispatchError {
 
 impl From<DispatchError> for &'static str {
 	fn from(err: DispatchError) -> &'static str {
+		use DispatchError::*;
 		match err {
-			DispatchError::Other(msg) => msg,
-			DispatchError::CannotLookup => "Cannot lookup",
-			DispatchError::BadOrigin => "Bad origin",
-			DispatchError::Module(ModuleError { message, .. }) =>
-				message.unwrap_or("Unknown module error"),
-			DispatchError::ConsumerRemaining => "Consumer remaining",
-			DispatchError::NoProviders => "No providers",
-			DispatchError::TooManyConsumers => "Too many consumers",
-			DispatchError::Token(e) => e.into(),
-			DispatchError::Arithmetic(e) => e.into(),
-			DispatchError::Transactional(e) => e.into(),
+			Other(msg) => msg,
+			CannotLookup => "Cannot lookup",
+			BadOrigin => "Bad origin",
+			Module(ModuleError { message, .. }) => message.unwrap_or("Unknown module error"),
+			ConsumerRemaining => "Consumer remaining",
+			NoProviders => "No providers",
+			TooManyConsumers => "Too many consumers",
+			Token(e) => e.into(),
+			Arithmetic(e) => e.into(),
+			Transactional(e) => e.into(),
+			Exhausted => "Resources exhausted",
+			Corruption => "State corrupt",
+			Unavailable => "Resource unavailable",
 		}
 	}
 }
@@ -698,33 +707,37 @@ where
 
 impl traits::Printable for DispatchError {
 	fn print(&self) {
+		use DispatchError::*;
 		"DispatchError".print();
 		match self {
-			Self::Other(err) => err.print(),
-			Self::CannotLookup => "Cannot lookup".print(),
-			Self::BadOrigin => "Bad origin".print(),
-			Self::Module(ModuleError { index, error, message }) => {
+			Other(err) => err.print(),
+			CannotLookup => "Cannot lookup".print(),
+			BadOrigin => "Bad origin".print(),
+			Module(ModuleError { index, error, message }) => {
 				index.print();
 				error.print();
 				if let Some(msg) = message {
 					msg.print();
 				}
 			},
-			Self::ConsumerRemaining => "Consumer remaining".print(),
-			Self::NoProviders => "No providers".print(),
-			Self::TooManyConsumers => "Too many consumers".print(),
-			Self::Token(e) => {
+			ConsumerRemaining => "Consumer remaining".print(),
+			NoProviders => "No providers".print(),
+			TooManyConsumers => "Too many consumers".print(),
+			Token(e) => {
 				"Token error: ".print();
 				<&'static str>::from(*e).print();
 			},
-			Self::Arithmetic(e) => {
+			Arithmetic(e) => {
 				"Arithmetic error: ".print();
 				<&'static str>::from(*e).print();
 			},
-			Self::Transactional(e) => {
+			Transactional(e) => {
 				"Transactional error: ".print();
 				<&'static str>::from(*e).print();
 			},
+			Exhausted => "Resources exhausted".print(),
+			Corruption => "State corrupt".print(),
+			Unavailable => "Resource unavailable".print(),
 		}
 	}
 }
diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs
index a64e3f25ef0417c9ee52b9d9ce94e7eb910c009c..3db0e5510057bd80ecb0707b920a25c5ba0544a1 100644
--- a/substrate/test-utils/runtime/src/lib.rs
+++ b/substrate/test-utils/runtime/src/lib.rs
@@ -37,8 +37,9 @@ use trie_db::{Trie, TrieMut};
 
 use cfg_if::cfg_if;
 use frame_support::{
+	dispatch::RawOrigin,
 	parameter_types,
-	traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem},
+	traits::{CallerTrait, ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem},
 	weights::{RuntimeDbWeight, Weight},
 };
 use frame_system::limits::{BlockLength, BlockWeights};
@@ -119,7 +120,7 @@ pub fn native_version() -> NativeVersion {
 }
 
 /// Calls in transactions.
-#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
+#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
 pub struct Transfer {
 	pub from: AccountId,
 	pub to: AccountId,
@@ -150,7 +151,7 @@ impl Transfer {
 }
 
 /// Extrinsic for test-runtime.
-#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
+#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
 pub enum Extrinsic {
 	AuthoritiesChange(Vec<AuthorityId>),
 	Transfer {
@@ -446,11 +447,22 @@ impl GetRuntimeBlockType for Runtime {
 #[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
 pub struct RuntimeOrigin;
 
-impl From<frame_system::Origin<Runtime>> for RuntimeOrigin {
-	fn from(_o: frame_system::Origin<Runtime>) -> Self {
+impl From<RawOrigin<<Runtime as frame_system::Config>::AccountId>> for RuntimeOrigin {
+	fn from(_: RawOrigin<<Runtime as frame_system::Config>::AccountId>) -> Self {
 		unimplemented!("Not required in tests!")
 	}
 }
+
+impl CallerTrait<<Runtime as frame_system::Config>::AccountId> for RuntimeOrigin {
+	fn into_system(self) -> Option<RawOrigin<<Runtime as frame_system::Config>::AccountId>> {
+		unimplemented!("Not required in tests!")
+	}
+
+	fn as_system_ref(&self) -> Option<&RawOrigin<<Runtime as frame_system::Config>::AccountId>> {
+		unimplemented!("Not required in tests!")
+	}
+}
+
 impl From<RuntimeOrigin> for Result<frame_system::Origin<Runtime>, RuntimeOrigin> {
 	fn from(_origin: RuntimeOrigin) -> Result<frame_system::Origin<Runtime>, RuntimeOrigin> {
 		unimplemented!("Not required in tests!")
@@ -482,6 +494,10 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin {
 		unimplemented!("Not required in tests!")
 	}
 
+	fn into_caller(self) -> Self::PalletsOrigin {
+		unimplemented!("Not required in tests!")
+	}
+
 	fn try_with_caller<R>(
 		self,
 		_f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
@@ -501,6 +517,9 @@ impl frame_support::traits::OriginTrait for RuntimeOrigin {
 	fn as_signed(self) -> Option<Self::AccountId> {
 		unimplemented!("Not required in tests!")
 	}
+	fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
+		unimplemented!("Not required in tests!")
+	}
 }
 
 #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
@@ -583,6 +602,12 @@ parameter_types! {
 		BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75));
 }
 
+impl From<frame_system::Call<Runtime>> for Extrinsic {
+	fn from(_: frame_system::Call<Runtime>) -> Self {
+		unimplemented!("Not required in tests!")
+	}
+}
+
 impl frame_system::Config for Runtime {
 	type BaseCallFilter = frame_support::traits::Everything;
 	type BlockWeights = RuntimeBlockWeights;