Skip to content

Commit

Permalink
expose test utilities to be used in BH paras (paritytech#2142)
Browse files Browse the repository at this point in the history
Signed-off-by: acatangiu <adrian@parity.io>
  • Loading branch information
acatangiu authored May 18, 2023
1 parent 4a40f97 commit d25a5c4
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 65 deletions.
2 changes: 1 addition & 1 deletion bin/runtime-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
8 changes: 3 additions & 5 deletions bin/runtime-common/src/messages_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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>,
Expand Down
96 changes: 41 additions & 55 deletions modules/parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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());
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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());

Expand Down
7 changes: 4 additions & 3 deletions modules/parachains/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
9 changes: 8 additions & 1 deletion primitives/test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
41 changes: 41 additions & 0 deletions primitives/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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)]
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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())
Expand Down

0 comments on commit d25a5c4

Please sign in to comment.