From 5d314eb03ed03d9030bb38b3d2e205f2f5c266ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bastian=20K=C3=B6cher?= <git@kchr.de>
Date: Wed, 27 Mar 2024 23:52:50 +0000
Subject: [PATCH] pallet-referenda: Detect incorrect pre-image length (#3850)

There has been a case that a referenda failed because the length given
to `submit` was incorrect. The pallet can actually check the length if
the pre-image already exists to ensure that these kind of issues are not
happening again.
---
 prdoc/pr_3850.prdoc                    | 15 +++++++++++++++
 substrate/frame/referenda/src/lib.rs   | 12 ++++++++++++
 substrate/frame/referenda/src/tests.rs | 16 ++++++++++++++++
 3 files changed, 43 insertions(+)
 create mode 100644 prdoc/pr_3850.prdoc

diff --git a/prdoc/pr_3850.prdoc b/prdoc/pr_3850.prdoc
new file mode 100644
index 00000000000..8f7ce16076e
--- /dev/null
+++ b/prdoc/pr_3850.prdoc
@@ -0,0 +1,15 @@
+title: Detect incorrect pre-image length when submitting a referenda
+
+doc:
+  - audience: Runtime User
+    description: |
+      When submitting a referenda the `proposal` is passed as argument.
+      The `proposal` is most of the time a reference to a `pre-image` and
+      which also contains the length of the `pre-image`. This pull request
+      adds some logic to check that if the `pre-image` already exists and if
+      it exists, it ensures that the length is passed correctly. This prevents
+      that the referenda can not be executed because of a mismatch of this
+      length.
+
+crates:
+  - name: pallet-referenda
diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs
index e616056c302..fbe27e1a478 100644
--- a/substrate/frame/referenda/src/lib.rs
+++ b/substrate/frame/referenda/src/lib.rs
@@ -424,6 +424,8 @@ pub mod pallet {
 		BadStatus,
 		/// The preimage does not exist.
 		PreimageNotExist,
+		/// The preimage is stored with a different length than the one provided.
+		PreimageStoredWithDifferentLength,
 	}
 
 	#[pallet::hooks]
@@ -462,6 +464,16 @@ pub mod pallet {
 			let proposal_origin = *proposal_origin;
 			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
 
+			// If the pre-image is already stored, ensure that it has the same length as given in
+			// `proposal`.
+			if let (Some(preimage_len), Some(proposal_len)) =
+				(proposal.lookup_hash().and_then(|h| T::Preimages::len(&h)), proposal.lookup_len())
+			{
+				if preimage_len != proposal_len {
+					return Err(Error::<T, I>::PreimageStoredWithDifferentLength.into())
+				}
+			}
+
 			let track =
 				T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?;
 			let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?;
diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs
index 8f51136de0b..52251fcbdbe 100644
--- a/substrate/frame/referenda/src/tests.rs
+++ b/substrate/frame/referenda/src/tests.rs
@@ -666,3 +666,19 @@ fn clear_metadata_works() {
 		}));
 	});
 }
+
+#[test]
+fn detects_incorrect_len() {
+	ExtBuilder::default().build_and_execute(|| {
+		let hash = note_preimage(1);
+		assert_noop!(
+			Referenda::submit(
+				RuntimeOrigin::signed(1),
+				Box::new(RawOrigin::Root.into()),
+				frame_support::traits::Bounded::Lookup { hash, len: 3 },
+				DispatchTime::At(1),
+			),
+			Error::<Test>::PreimageStoredWithDifferentLength
+		);
+	});
+}
-- 
GitLab