From 564cc5ead77fddd3e4b278dcf3959d9e143c89e1 Mon Sep 17 00:00:00 2001
From: Adrian Catangiu <adrian@parity.io>
Date: Thu, 18 May 2023 18:08:15 +0300
Subject: [PATCH] expose test utilities to be used in BH paras (#2142)

Signed-off-by: acatangiu <adrian@parity.io>
---
 bridges/bin/runtime-common/src/lib.rs         |  2 +-
 .../runtime-common/src/messages_generation.rs |  8 +-
 bridges/modules/parachains/src/lib.rs         | 96 ++++++++-----------
 bridges/modules/parachains/src/mock.rs        |  7 +-
 bridges/primitives/test-utils/Cargo.toml      |  9 +-
 bridges/primitives/test-utils/src/lib.rs      | 41 ++++++++
 6 files changed, 98 insertions(+), 65 deletions(-)

diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs
index 12b096492cd..546d4388471 100644
--- a/bridges/bin/runtime-common/src/lib.rs
+++ b/bridges/bin/runtime-common/src/lib.rs
@@ -28,12 +28,12 @@ pub mod messages;
 pub mod messages_api;
 pub mod messages_benchmarking;
 pub mod messages_call_ext;
+pub mod messages_generation;
 pub mod messages_xcm_extension;
 pub mod parachains_benchmarking;
 pub mod priority_calculator;
 pub mod refund_relayer_extension;
 
-mod messages_generation;
 mod mock;
 
 #[cfg(feature = "integrity-test")]
diff --git a/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/bin/runtime-common/src/messages_generation.rs
index 29a869a5c87..8dbf3abd683 100644
--- a/bridges/bin/runtime-common/src/messages_generation.rs
+++ b/bridges/bin/runtime-common/src/messages_generation.rs
@@ -16,8 +16,6 @@
 
 //! Helpers for generating message storage proofs, that are used by tests and by benchmarks.
 
-#![cfg(any(feature = "runtime-benchmarks", test))]
-
 use crate::messages::{BridgedChain, HashOf, HasherOf, MessageBridge};
 
 use bp_messages::{
@@ -29,19 +27,19 @@ use sp_std::{ops::RangeInclusive, prelude::*};
 use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
 
 /// Simple and correct message data encode function.
-pub(crate) fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option<Vec<u8>> {
+pub fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option<Vec<u8>> {
 	Some(m.encode())
 }
 
 /// Simple and correct outbound lane data encode function.
-pub(crate) fn encode_lane_data(d: &OutboundLaneData) -> Vec<u8> {
+pub fn encode_lane_data(d: &OutboundLaneData) -> Vec<u8> {
 	d.encode()
 }
 
 /// Prepare storage proof of given messages.
 ///
 /// Returns state trie root and nodes with prepared messages.
-pub(crate) fn prepare_messages_storage_proof<B>(
+pub fn prepare_messages_storage_proof<B>(
 	lane: LaneId,
 	message_nonces: RangeInclusive<MessageNonce>,
 	outbound_lane_data: Option<OutboundLaneData>,
diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs
index 5a393af7cc4..c2052e3d4eb 100644
--- a/bridges/modules/parachains/src/lib.rs
+++ b/bridges/modules/parachains/src/lib.rs
@@ -701,16 +701,17 @@ pub(crate) mod tests {
 	use crate::mock::{
 		run_test, test_relay_header, BigParachainHeader, RegularParachainHasher,
 		RegularParachainHeader, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime,
-		PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID,
+		UNTRACKED_PARACHAIN_ID,
 	};
+	use bp_test_utils::prepare_parachain_heads_proof;
 	use codec::Encode;
 
 	use bp_parachains::{
 		BestParaHeadHash, BridgeParachainCall, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider,
 	};
 	use bp_runtime::{
-		record_all_trie_keys, BasicOperatingMode, OwnedBridgeModuleError,
-		StorageDoubleMapKeyProvider, StorageMapKeyProvider,
+		BasicOperatingMode, OwnedBridgeModuleError, StorageDoubleMapKeyProvider,
+		StorageMapKeyProvider,
 	};
 	use bp_test_utils::{
 		authority_list, generate_owned_bridge_module_tests, make_default_justification,
@@ -725,7 +726,6 @@ pub(crate) mod tests {
 	use frame_system::{EventRecord, Pallet as System, Phase};
 	use sp_core::Hasher;
 	use sp_runtime::{traits::Header as HeaderT, DispatchError};
-	use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
 
 	type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
 	type WeightInfo = <TestRuntime as Config>::WeightInfo;
@@ -768,32 +768,6 @@ pub(crate) mod tests {
 		hash
 	}
 
-	pub(crate) fn prepare_parachain_heads_proof(
-		heads: Vec<(u32, ParaHead)>,
-	) -> (RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) {
-		let mut parachains = Vec::with_capacity(heads.len());
-		let mut root = Default::default();
-		let mut mdb = MemoryDB::default();
-		{
-			let mut trie = TrieDBMutBuilderV1::<RelayBlockHasher>::new(&mut mdb, &mut root).build();
-			for (parachain, head) in heads {
-				let storage_key =
-					parachain_head_storage_key_at_source(PARAS_PALLET_NAME, ParaId(parachain));
-				trie.insert(&storage_key.0, &head.encode())
-					.map_err(|_| "TrieMut::insert has failed")
-					.expect("TrieMut::insert should not fail in tests");
-				parachains.push((ParaId(parachain), head.hash()));
-			}
-		}
-
-		// generate storage proof to be delivered to This chain
-		let storage_proof = record_all_trie_keys::<LayoutV1<RelayBlockHasher>, _>(&mdb, &root)
-			.map_err(|_| "record_all_trie_keys has failed")
-			.expect("record_all_trie_keys should not fail in benchmarks");
-
-		(root, ParaHeadsProof(storage_proof), parachains)
-	}
-
 	fn initial_best_head(parachain: u32) -> ParaInfo {
 		ParaInfo {
 			best_head_hash: BestParaHeadHash {
@@ -875,7 +849,7 @@ pub(crate) mod tests {
 	#[test]
 	fn submit_parachain_heads_checks_operating_mode() {
 		let (state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 0))]);
 
 		run_test(|| {
 			initialize(state_root);
@@ -906,7 +880,10 @@ pub(crate) mod tests {
 	#[test]
 	fn imports_initial_parachain_heads() {
 		let (state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 0)), (3, head_data(3, 10))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![
+				(1, head_data(1, 0)),
+				(3, head_data(3, 10)),
+			]);
 		run_test(|| {
 			initialize(state_root);
 
@@ -985,9 +962,9 @@ pub(crate) mod tests {
 	#[test]
 	fn imports_parachain_heads_is_able_to_progress() {
 		let (state_root_5, proof_5, parachains_5) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 5))]);
 		let (state_root_10, proof_10, parachains_10) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 10))]);
 		run_test(|| {
 			// start with relay block #0 and import head#5 of parachain#1
 			initialize(state_root_5);
@@ -1083,11 +1060,12 @@ pub(crate) mod tests {
 
 	#[test]
 	fn ignores_untracked_parachain() {
-		let (state_root, proof, parachains) = prepare_parachain_heads_proof(vec![
-			(1, head_data(1, 5)),
-			(UNTRACKED_PARACHAIN_ID, head_data(1, 5)),
-			(2, head_data(1, 5)),
-		]);
+		let (state_root, proof, parachains) =
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![
+				(1, head_data(1, 5)),
+				(UNTRACKED_PARACHAIN_ID, head_data(1, 5)),
+				(2, head_data(1, 5)),
+			]);
 		run_test(|| {
 			// start with relay block #0 and try to import head#5 of parachain#1 and untracked
 			// parachain
@@ -1160,7 +1138,7 @@ pub(crate) mod tests {
 	#[test]
 	fn does_nothing_when_already_imported_this_head_at_previous_relay_header() {
 		let (state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 0))]);
 		run_test(|| {
 			// import head#0 of parachain#1 at relay block#0
 			initialize(state_root);
@@ -1220,9 +1198,9 @@ pub(crate) mod tests {
 	#[test]
 	fn does_nothing_when_already_imported_head_at_better_relay_header() {
 		let (state_root_5, proof_5, parachains_5) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 5))]);
 		let (state_root_10, proof_10, parachains_10) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 10))]);
 		run_test(|| {
 			// start with relay block #0
 			initialize(state_root_5);
@@ -1314,7 +1292,10 @@ pub(crate) mod tests {
 	#[test]
 	fn does_nothing_when_parachain_head_is_too_large() {
 		let (state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5)), (4, big_head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![
+				(1, head_data(1, 5)),
+				(4, big_head_data(1, 5)),
+			]);
 		run_test(|| {
 			// start with relay block #0 and try to import head#5 of parachain#1 and big parachain
 			initialize(state_root);
@@ -1368,8 +1349,9 @@ pub(crate) mod tests {
 
 			// import exactly `HeadsToKeep` headers
 			for i in 0..heads_to_keep {
-				let (state_root, proof, parachains) =
-					prepare_parachain_heads_proof(vec![(1, head_data(1, i))]);
+				let (state_root, proof, parachains) = prepare_parachain_heads_proof::<
+					RegularParachainHeader,
+				>(vec![(1, head_data(1, i))]);
 				if i == 0 {
 					initialize(state_root);
 				} else {
@@ -1389,8 +1371,9 @@ pub(crate) mod tests {
 			}
 
 			// import next relay chain header and next parachain head
-			let (state_root, proof, parachains) =
-				prepare_parachain_heads_proof(vec![(1, head_data(1, heads_to_keep))]);
+			let (state_root, proof, parachains) = prepare_parachain_heads_proof::<
+				RegularParachainHeader,
+			>(vec![(1, head_data(1, heads_to_keep))]);
 			proceed(heads_to_keep, state_root);
 			let expected_weight = weight_of_import_parachain_1_head(&proof, true);
 			let result = import_parachain_1_head(heads_to_keep, state_root, parachains, proof);
@@ -1411,7 +1394,7 @@ pub(crate) mod tests {
 	#[test]
 	fn fails_on_unknown_relay_chain_block() {
 		let (state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 5))]);
 		run_test(|| {
 			// start with relay block #0
 			initialize(state_root);
@@ -1427,7 +1410,7 @@ pub(crate) mod tests {
 	#[test]
 	fn fails_on_invalid_storage_proof() {
 		let (_state_root, proof, parachains) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 5))]);
 		run_test(|| {
 			// start with relay block #0
 			initialize(Default::default());
@@ -1445,11 +1428,11 @@ pub(crate) mod tests {
 	#[test]
 	fn is_not_rewriting_existing_head_if_failed_to_read_updated_head() {
 		let (state_root_5, proof_5, parachains_5) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 5))]);
 		let (state_root_10_at_20, proof_10_at_20, parachains_10_at_20) =
-			prepare_parachain_heads_proof(vec![(2, head_data(2, 10))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(2, head_data(2, 10))]);
 		let (state_root_10_at_30, proof_10_at_30, parachains_10_at_30) =
-			prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 10))]);
 		run_test(|| {
 			// we've already imported head#5 of parachain#1 at relay block#10
 			initialize(state_root_5);
@@ -1517,7 +1500,8 @@ pub(crate) mod tests {
 
 	#[test]
 	fn ignores_parachain_head_if_it_is_missing_from_storage_proof() {
-		let (state_root, proof, _) = prepare_parachain_heads_proof(vec![]);
+		let (state_root, proof, _) =
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![]);
 		let parachains = vec![(ParaId(2), Default::default())];
 		run_test(|| {
 			initialize(state_root);
@@ -1542,7 +1526,8 @@ pub(crate) mod tests {
 
 	#[test]
 	fn ignores_parachain_head_if_parachain_head_hash_is_wrong() {
-		let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
+		let (state_root, proof, _) =
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 0))]);
 		let parachains = vec![(ParaId(1), head_data(1, 10).hash())];
 		run_test(|| {
 			initialize(state_root);
@@ -1569,7 +1554,8 @@ pub(crate) mod tests {
 
 	#[test]
 	fn test_bridge_parachain_call_is_correctly_defined() {
-		let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
+		let (state_root, proof, _) =
+			prepare_parachain_heads_proof::<RegularParachainHeader>(vec![(1, head_data(1, 0))]);
 		let parachains = vec![(ParaId(2), Default::default())];
 		let relay_header_id = (0, test_relay_header(0, state_root).hash());
 
diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs
index 3086adc1cc2..0a61d91d7b2 100644
--- a/bridges/modules/parachains/src/mock.rs
+++ b/bridges/modules/parachains/src/mock.rs
@@ -250,9 +250,10 @@ impl pallet_bridge_parachains::benchmarking::Config<()> for TestRuntime {
 	) {
 		// in mock run we only care about benchmarks correctness, not the benchmark results
 		// => ignore size related arguments
-		let (state_root, proof, parachains) = crate::tests::prepare_parachain_heads_proof(
-			parachains.iter().map(|p| (p.0, crate::tests::head_data(p.0, 1))).collect(),
-		);
+		let (state_root, proof, parachains) =
+			bp_test_utils::prepare_parachain_heads_proof::<RegularParachainHeader>(
+				parachains.iter().map(|p| (p.0, crate::tests::head_data(p.0, 1))).collect(),
+			);
 		let relay_genesis_hash = crate::tests::initialize(state_root);
 		(0, relay_genesis_hash, proof, parachains)
 	}
diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml
index 5ed835857d1..2e2af99332e 100644
--- a/bridges/primitives/test-utils/Cargo.toml
+++ b/bridges/primitives/test-utils/Cargo.toml
@@ -7,23 +7,30 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
 bp-header-chain = { path = "../header-chain", default-features = false  }
+bp-parachains = { path = "../parachains", default-features = false }
+bp-polkadot-core = { path = "../polkadot-core", default-features = false  }
+bp-runtime = { path = "../runtime", default-features = false }
 codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false }
 ed25519-dalek = { version = "1.0", default-features = false, features = ["u64_backend"] }
 finality-grandpa = { version = "0.16.2", default-features = false }
 sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false  }
+sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 
 [features]
 default = ["std"]
 std = [
 	"bp-header-chain/std",
+	"bp-polkadot-core/std",
 	"codec/std",
 	"ed25519-dalek/std",
 	"finality-grandpa/std",
 	"sp-application-crypto/std",
 	"sp-consensus-grandpa/std",
+	"sp-core/std",
 	"sp-runtime/std",
 	"sp-std/std",
 ]
diff --git a/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs
index 6bb4adbf450..5a7d0cca279 100644
--- a/bridges/primitives/test-utils/src/lib.rs
+++ b/bridges/primitives/test-utils/src/lib.rs
@@ -19,10 +19,14 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use bp_header_chain::justification::{required_justification_precommits, GrandpaJustification};
+use bp_parachains::parachain_head_storage_key_at_source;
+use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
+use bp_runtime::record_all_trie_keys;
 use codec::Encode;
 use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, AuthorityWeight, SetId};
 use sp_runtime::traits::{Header as HeaderT, One, Zero};
 use sp_std::prelude::*;
+use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
 
 // Re-export all our test account utilities
 pub use keyring::*;
@@ -31,6 +35,7 @@ mod keyring;
 
 pub const TEST_GRANDPA_ROUND: u64 = 1;
 pub const TEST_GRANDPA_SET_ID: SetId = 1;
+pub const PARAS_PALLET_NAME: &str = "Paras";
 
 /// Configuration parameters when generating test GRANDPA justifications.
 #[derive(Clone)]
@@ -161,6 +166,33 @@ fn generate_chain<H: HeaderT>(fork_id: u32, depth: u32, ancestor: &H) -> Vec<H>
 	headers
 }
 
+/// Make valid proof for parachain `heads`
+pub fn prepare_parachain_heads_proof<H: HeaderT>(
+	heads: Vec<(u32, ParaHead)>,
+) -> (H::Hash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) {
+	let mut parachains = Vec::with_capacity(heads.len());
+	let mut root = Default::default();
+	let mut mdb = MemoryDB::default();
+	{
+		let mut trie = TrieDBMutBuilderV1::<H::Hashing>::new(&mut mdb, &mut root).build();
+		for (parachain, head) in heads {
+			let storage_key =
+				parachain_head_storage_key_at_source(PARAS_PALLET_NAME, ParaId(parachain));
+			trie.insert(&storage_key.0, &head.encode())
+				.map_err(|_| "TrieMut::insert has failed")
+				.expect("TrieMut::insert should not fail in tests");
+			parachains.push((ParaId(parachain), head.hash()));
+		}
+	}
+
+	// generate storage proof to be delivered to This chain
+	let storage_proof = record_all_trie_keys::<LayoutV1<H::Hashing>, _>(&mdb, &root)
+		.map_err(|_| "record_all_trie_keys has failed")
+		.expect("record_all_trie_keys should not fail in benchmarks");
+
+	(root, ParaHeadsProof(storage_proof), parachains)
+}
+
 /// Create signed precommit with given target.
 pub fn signed_precommit<H: HeaderT>(
 	signer: &Account,
@@ -207,6 +239,15 @@ pub fn test_header<H: HeaderT>(number: H::Number) -> H {
 	header
 }
 
+/// Get a header for testing with given `state_root`.
+///
+/// The correct parent hash will be used if given a non-zero header.
+pub fn test_header_with_root<H: HeaderT>(number: H::Number, state_root: H::Hash) -> H {
+	let mut header: H = test_header(number);
+	header.set_state_root(state_root);
+	header
+}
+
 /// Convenience function for generating a Header ID at a given block number.
 pub fn header_id<H: HeaderT>(index: u8) -> (H::Hash, H::Number) {
 	(test_header::<H>(index.into()).hash(), index.into())
-- 
GitLab