From 564cc5ead77fddd3e4b278dcf3959d9e143c89e1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu 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 --- 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 12b096492cd4..546d4388471c 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 29a869a5c871..8dbf3abd683c 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> { +pub fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option> { Some(m.encode()) } /// Simple and correct outbound lane data encode function. -pub(crate) fn encode_lane_data(d: &OutboundLaneData) -> Vec { +pub fn encode_lane_data(d: &OutboundLaneData) -> Vec { d.encode() } /// Prepare storage proof of given messages. /// /// Returns state trie root and nodes with prepared messages. -pub(crate) fn prepare_messages_storage_proof( +pub fn prepare_messages_storage_proof( lane: LaneId, message_nonces: RangeInclusive, outbound_lane_data: Option, diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 5a393af7cc4e..c2052e3d4ebe 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 = ::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::::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::, _>(&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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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 3086adc1cc2e..0a61d91d7b2d 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::( + 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 5ed835857d1c..2e2af99332ea 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 6bb4adbf4509..5a7d0cca279a 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(fork_id: u32, depth: u32, ancestor: &H) -> Vec headers } +/// Make valid proof for parachain `heads` +pub fn prepare_parachain_heads_proof( + 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::::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::, _>(&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( signer: &Account, @@ -207,6 +239,15 @@ pub fn test_header(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(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(index: u8) -> (H::Hash, H::Number) { (test_header::(index.into()).hash(), index.into())