From 494167a05bd197e9f5c230ca927317f8e6d58c02 Mon Sep 17 00:00:00 2001
From: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Date: Tue, 24 May 2022 07:23:05 +0100
Subject: [PATCH] Optimize offchain worker memory usage a bit.  (#11454)

* add missing events to elections fallback

* Merged

* add some logs and stuff

* undo a bunch of things

* undo lock file

* remove unused err

* fix build
---
 .../client/allocator/src/freeing_bump.rs      |  1 -
 .../src/unsigned.rs                           | 59 +++++++++++--------
 .../frame/support/src/storage/types/nmap.rs   |  4 +-
 .../npos-elections/src/assignments.rs         | 23 ++++----
 .../cli/src/commands/execute_block.rs         |  5 ++
 .../cli/src/commands/offchain_worker.rs       |  5 ++
 .../utils/frame/try-runtime/cli/src/lib.rs    |  2 +-
 7 files changed, 58 insertions(+), 41 deletions(-)

diff --git a/substrate/client/allocator/src/freeing_bump.rs b/substrate/client/allocator/src/freeing_bump.rs
index f14c31c79c4..79d6fca6f91 100644
--- a/substrate/client/allocator/src/freeing_bump.rs
+++ b/substrate/client/allocator/src/freeing_bump.rs
@@ -216,7 +216,6 @@ impl Link {
 /// |            0 | next element link |
 /// +--------------+-------------------+
 /// ```
-/// 
 /// ## Occupied header
 /// ```ignore
 /// 64             32                  0
diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs
index 9a1b52d3545..de25355f0ca 100644
--- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs
+++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs
@@ -169,27 +169,6 @@ impl<T: Config> Pallet<T> {
 		Ok((RawSolution { solution, score, round }, size))
 	}
 
-	/// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which
-	/// is ready to be submitted to the chain.
-	///
-	/// Will always reduce the solution as well.
-	pub fn prepare_election_result<Accuracy: PerThing128>(
-		election_result: ElectionResult<T::AccountId, Accuracy>,
-	) -> Result<(RawSolution<SolutionOf<T::MinerConfig>>, SolutionOrSnapshotSize), MinerError> {
-		let RoundSnapshot { voters, targets } =
-			Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?;
-		let desired_targets = Self::desired_targets().ok_or(MinerError::SnapshotUnAvailable)?;
-		let (solution, score, size) =
-			Miner::<T::MinerConfig>::prepare_election_result_with_snapshot(
-				election_result,
-				voters,
-				targets,
-				desired_targets,
-			)?;
-		let round = Self::round();
-		Ok((RawSolution { solution, score, round }, size))
-	}
-
 	/// Attempt to restore a solution from cache. Otherwise, compute it fresh. Either way, submit
 	/// if our call's score is greater than that of the cached solution.
 	pub fn restore_or_compute_then_maybe_submit() -> Result<(), MinerError> {
@@ -441,7 +420,10 @@ impl<T: MinerConfig> Miner<T> {
 			})
 	}
 
-	/// Same as [`Pallet::prepare_election_result`], but the input snapshot mut be given as inputs.
+	/// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which
+	/// is ready to be submitted to the chain.
+	///
+	/// Will always reduce the solution as well.
 	pub fn prepare_election_result_with_snapshot<Accuracy: PerThing128>(
 		election_result: ElectionResult<T::AccountId, Accuracy>,
 		voters: Vec<(T::AccountId, VoteWeight, BoundedVec<T::AccountId, T::MaxVotesPerVoter>)>,
@@ -1118,7 +1100,19 @@ mod tests {
 						distribution: vec![(10, PerU16::one())],
 					}],
 				};
-				let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap();
+
+				let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap();
+				let desired_targets = MultiPhase::desired_targets().unwrap();
+
+				let (raw, score, witness) =
+					Miner::<Runtime>::prepare_election_result_with_snapshot(
+						result,
+						voters.clone(),
+						targets.clone(),
+						desired_targets,
+					)
+					.unwrap();
+				let solution = RawSolution { solution: raw, score, round: MultiPhase::round() };
 				assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution));
 				assert_ok!(MultiPhase::submit_unsigned(
 					Origin::none(),
@@ -1139,7 +1133,14 @@ mod tests {
 						},
 					],
 				};
-				let (solution, _) = MultiPhase::prepare_election_result(result).unwrap();
+				let (raw, score, _) = Miner::<Runtime>::prepare_election_result_with_snapshot(
+					result,
+					voters.clone(),
+					targets.clone(),
+					desired_targets,
+				)
+				.unwrap();
+				let solution = RawSolution { solution: raw, score, round: MultiPhase::round() };
 				// 12 is not 50% more than 10
 				assert_eq!(solution.score.minimal_stake, 12);
 				assert_noop!(
@@ -1161,7 +1162,15 @@ mod tests {
 						},
 					],
 				};
-				let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap();
+				let (raw, score, witness) =
+					Miner::<Runtime>::prepare_election_result_with_snapshot(
+						result,
+						voters.clone(),
+						targets.clone(),
+						desired_targets,
+					)
+					.unwrap();
+				let solution = RawSolution { solution: raw, score, round: MultiPhase::round() };
 				assert_eq!(solution.score.minimal_stake, 17);
 
 				// and it is fine
diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs
index 5faeb5d8cac..a15c7482105 100755
--- a/substrate/frame/support/src/storage/types/nmap.rs
+++ b/substrate/frame/support/src/storage/types/nmap.rs
@@ -544,7 +544,7 @@ mod test {
 	use crate::{
 		hash::{StorageHasher as _, *},
 		metadata::{StorageEntryModifier, StorageHasher},
-		storage::types::{Key, Key as NMapKey, ValueQuery},
+		storage::types::{Key, ValueQuery},
 	};
 	use sp_io::{hashing::twox_128, TestExternalities};
 
@@ -590,7 +590,7 @@ mod test {
 
 			{
 				#[crate::storage_alias]
-				type Foo = StorageNMap<test, (NMapKey<Blake2_128Concat, u16>), u32>;
+				type Foo = StorageNMap<test, (Key<Blake2_128Concat, u16>), u32>;
 
 				assert_eq!(Foo::contains_key((3,)), true);
 				assert_eq!(Foo::get((3,)), Some(10));
diff --git a/substrate/primitives/npos-elections/src/assignments.rs b/substrate/primitives/npos-elections/src/assignments.rs
index 9422ccdf658..fc88ef40010 100644
--- a/substrate/primitives/npos-elections/src/assignments.rs
+++ b/substrate/primitives/npos-elections/src/assignments.rs
@@ -120,18 +120,17 @@ impl<AccountId> StakedAssignment<AccountId> {
 		AccountId: IdentifierT,
 	{
 		let stake = self.total();
-		let distribution = self
-			.distribution
-			.into_iter()
-			.filter_map(|(target, w)| {
-				let per_thing = P::from_rational(w, stake);
-				if per_thing == Bounded::min_value() {
-					None
-				} else {
-					Some((target, per_thing))
-				}
-			})
-			.collect::<Vec<(AccountId, P)>>();
+		// most likely, the size of the staked assignment and normal assignments will be the same,
+		// so we pre-allocate it to prevent a sudden 2x allocation. `filter_map` starts with a size
+		// of 0 by default.
+		// https://www.reddit.com/r/rust/comments/3spfh1/does_collect_allocate_more_than_once_while/
+		let mut distribution = Vec::<(AccountId, P)>::with_capacity(self.distribution.len());
+		self.distribution.into_iter().for_each(|(target, w)| {
+			let per_thing = P::from_rational(w, stake);
+			if per_thing != Bounded::min_value() {
+				distribution.push((target, per_thing));
+			}
+		});
 
 		Assignment { who: self.who, distribution }
 	}
diff --git a/substrate/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/substrate/utils/frame/try-runtime/cli/src/commands/execute_block.rs
index 12c36955c26..204acd87931 100644
--- a/substrate/utils/frame/try-runtime/cli/src/commands/execute_block.rs
+++ b/substrate/utils/frame/try-runtime/cli/src/commands/execute_block.rs
@@ -142,6 +142,11 @@ where
 			.overwrite_online_at(parent_hash.to_owned());
 
 		let builder = if command.overwrite_wasm_code {
+			log::info!(
+				target: LOG_TARGET,
+				"replacing the in-storage :code: with the local code from {}'s chain_spec (your local repo)",
+				config.chain_spec.name(),
+			);
 			let (code_key, code) = extract_code(&config.chain_spec)?;
 			builder.inject_hashed_key_value(&[(code_key, code)])
 		} else {
diff --git a/substrate/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/substrate/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs
index 9aad9018297..50780f4513b 100644
--- a/substrate/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs
+++ b/substrate/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs
@@ -131,6 +131,11 @@ where
 		let builder = command.state.builder::<Block>()?;
 
 		let builder = if command.overwrite_wasm_code {
+			log::info!(
+				target: LOG_TARGET,
+				"replacing the in-storage :code: with the local code from {}'s chain_spec (your local repo)",
+				config.chain_spec.name(),
+			);
 			let (code_key, code) = extract_code(&config.chain_spec)?;
 			builder.inject_hashed_key_value(&[(code_key, code)])
 		} else {
diff --git a/substrate/utils/frame/try-runtime/cli/src/lib.rs b/substrate/utils/frame/try-runtime/cli/src/lib.rs
index 71d258a6898..c09a33cf3f1 100644
--- a/substrate/utils/frame/try-runtime/cli/src/lib.rs
+++ b/substrate/utils/frame/try-runtime/cli/src/lib.rs
@@ -722,7 +722,7 @@ pub(crate) fn state_machine_call<Block: BlockT, D: NativeExecutionDispatch + 'st
 		sp_core::testing::TaskExecutor::new(),
 	)
 	.execute(execution.into())
-	.map_err(|e| format!("failed to execute 'TryRuntime_on_runtime_upgrade': {}", e))
+	.map_err(|e| format!("failed to execute '{}': {}", method, e))
 	.map_err::<sc_cli::Error, _>(Into::into)?;
 
 	Ok((changes, encoded_results))
-- 
GitLab