Files
pezkuwi-subxt/pallets/parachain-system/src/validate_block/tests.rs
T
Oliver Tale-Yazdi c312f0b9a6 Fix Clippy (#2522)
* Import Clippy config from Polkadot

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Auto clippy fix

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* No tabs in comments

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Prefer matches

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Dont drop references

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Trivial

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Refactor

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* add clippy to ci

* Clippy reborrow

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update client/pov-recovery/src/lib.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update client/pov-recovery/src/lib.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Partially revert 'Prefer matches'

Using matches! instead of match does give less compiler
checks as per review from @chevdor.

Partially reverts 8c0609677f3ea040f77fffd5be6facf7c3fec95c

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update .cargo/config.toml

Co-authored-by: Chevdor <chevdor@users.noreply.github.com>

* Revert revert 💩

Should be fine to use matches! macro since it is an explicit whitelist,
not wildcard matching.

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: alvicsam <alvicsam@gmail.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Chevdor <chevdor@users.noreply.github.com>
Co-authored-by: parity-processbot <>
2023-05-06 08:01:03 +02:00

322 lines
10 KiB
Rust

// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use codec::{Decode, DecodeAll, Encode};
use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
use cumulus_test_client::{
generate_extrinsic,
runtime::{Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY},
transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData,
InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams,
};
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use sp_keyring::AccountKeyring::*;
use sp_runtime::traits::Header as HeaderT;
use std::{env, process::Command};
use crate::validate_block::MemoryOptimizedValidationParams;
fn call_validate_block_encoded_header(
parent_head: Header,
block_data: ParachainBlockData<Block>,
relay_parent_storage_root: Hash,
) -> cumulus_test_client::ExecutorResult<Vec<u8>> {
cumulus_test_client::validate_block(
ValidationParams {
block_data: BlockData(block_data.encode()),
parent_head: HeadData(parent_head.encode()),
relay_parent_number: 1,
relay_parent_storage_root,
},
WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"),
)
.map(|v| v.head_data.0)
}
fn call_validate_block(
parent_head: Header,
block_data: ParachainBlockData<Block>,
relay_parent_storage_root: Hash,
) -> cumulus_test_client::ExecutorResult<Header> {
call_validate_block_encoded_header(parent_head, block_data, relay_parent_storage_root)
.map(|v| Header::decode(&mut &v[..]).expect("Decodes `Header`."))
}
fn create_test_client() -> (Client, Header) {
let client = TestClientBuilder::new()
// NOTE: this allows easier debugging
.set_execution_strategy(sc_client_api::ExecutionStrategy::NativeWhenPossible)
.build();
let genesis_header = client
.header(client.chain_info().genesis_hash)
.ok()
.flatten()
.expect("Genesis header exists; qed");
(client, genesis_header)
}
struct TestBlockData {
block: ParachainBlockData<Block>,
validation_data: PersistedValidationData,
}
fn build_block_with_witness(
client: &Client,
extra_extrinsics: Vec<UncheckedExtrinsic>,
parent_head: Header,
sproof_builder: RelayStateSproofBuilder,
) -> TestBlockData {
let (relay_parent_storage_root, _) = sproof_builder.clone().into_state_root_and_proof();
let mut validation_data = PersistedValidationData {
relay_parent_number: 1,
parent_head: parent_head.encode().into(),
..Default::default()
};
let mut builder = client.init_block_builder(Some(validation_data.clone()), sproof_builder);
validation_data.relay_parent_storage_root = relay_parent_storage_root;
extra_extrinsics.into_iter().for_each(|e| builder.push(e).unwrap());
let block = builder.build_parachain_block(*parent_head.state_root());
TestBlockData { block, validation_data }
}
#[test]
fn validate_block_no_extra_extrinsics() {
sp_tracing::try_init_simple();
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } =
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
let header = block.header().clone();
let res_header =
call_validate_block(parent_head, block, validation_data.relay_parent_storage_root)
.expect("Calls `validate_block`");
assert_eq!(header, res_header);
}
#[test]
fn validate_block_with_extra_extrinsics() {
sp_tracing::try_init_simple();
let (client, parent_head) = create_test_client();
let extra_extrinsics = vec![
transfer(&client, Alice, Bob, 69),
transfer(&client, Bob, Charlie, 100),
transfer(&client, Charlie, Alice, 500),
];
let TestBlockData { block, validation_data } = build_block_with_witness(
&client,
extra_extrinsics,
parent_head.clone(),
Default::default(),
);
let header = block.header().clone();
let res_header =
call_validate_block(parent_head, block, validation_data.relay_parent_storage_root)
.expect("Calls `validate_block`");
assert_eq!(header, res_header);
}
#[test]
fn validate_block_returns_custom_head_data() {
sp_tracing::try_init_simple();
let expected_header = vec![1, 3, 3, 7, 4, 5, 6];
let (client, parent_head) = create_test_client();
let extra_extrinsics = vec![
transfer(&client, Alice, Bob, 69),
generate_extrinsic(
&client,
Charlie,
TestPalletCall::set_custom_validation_head_data {
custom_header: expected_header.clone(),
},
),
transfer(&client, Bob, Charlie, 100),
];
let TestBlockData { block, validation_data } = build_block_with_witness(
&client,
extra_extrinsics,
parent_head.clone(),
Default::default(),
);
let header = block.header().clone();
assert_ne!(expected_header, header.encode());
let res_header = call_validate_block_encoded_header(
parent_head,
block,
validation_data.relay_parent_storage_root,
)
.expect("Calls `validate_block`");
assert_eq!(expected_header, res_header);
}
#[test]
fn validate_block_invalid_parent_hash() {
sp_tracing::try_init_simple();
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } =
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
let (mut header, extrinsics, witness) = block.deconstruct();
header.set_parent_hash(Hash::from_low_u64_be(1));
let block_data = ParachainBlockData::new(header, extrinsics, witness);
call_validate_block(parent_head, block_data, validation_data.relay_parent_storage_root)
.unwrap_err();
} else {
let output = Command::new(env::current_exe().unwrap())
.args(["validate_block_invalid_parent_hash", "--", "--nocapture"])
.env("RUN_TEST", "1")
.output()
.expect("Runs the test");
assert!(output.status.success());
assert!(dbg!(String::from_utf8(output.stderr).unwrap()).contains("Invalid parent hash"));
}
}
#[test]
fn validate_block_fails_on_invalid_validation_data() {
sp_tracing::try_init_simple();
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, .. } =
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
call_validate_block(parent_head, block, Hash::random()).unwrap_err();
} else {
let output = Command::new(env::current_exe().unwrap())
.args(["validate_block_fails_on_invalid_validation_data", "--", "--nocapture"])
.env("RUN_TEST", "1")
.output()
.expect("Runs the test");
assert!(output.status.success());
assert!(dbg!(String::from_utf8(output.stderr).unwrap())
.contains("Relay parent storage root doesn't match"));
}
}
#[test]
fn check_inherent_fails_on_validate_block_as_expected() {
sp_tracing::try_init_simple();
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } = build_block_with_witness(
&client,
Vec::new(),
parent_head.clone(),
RelayStateSproofBuilder { current_slot: 1337.into(), ..Default::default() },
);
call_validate_block(parent_head, block, validation_data.relay_parent_storage_root)
.unwrap_err();
} else {
let output = Command::new(env::current_exe().unwrap())
.args(["check_inherent_fails_on_validate_block_as_expected", "--", "--nocapture"])
.env("RUN_TEST", "1")
.output()
.expect("Runs the test");
assert!(output.status.success());
assert!(
dbg!(String::from_utf8(output.stderr).unwrap()).contains("Checking inherents failed")
);
}
}
#[test]
fn check_inherents_are_unsigned_and_before_all_other_extrinsics() {
sp_tracing::try_init_simple();
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } =
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
let (header, mut extrinsics, proof) = block.deconstruct();
extrinsics.insert(0, transfer(&client, Alice, Bob, 69));
call_validate_block(
parent_head,
ParachainBlockData::new(header, extrinsics, proof),
validation_data.relay_parent_storage_root,
)
.unwrap_err();
} else {
let output = Command::new(env::current_exe().unwrap())
.args([
"check_inherents_are_unsigned_and_before_all_other_extrinsics",
"--",
"--nocapture",
])
.env("RUN_TEST", "1")
.output()
.expect("Runs the test");
assert!(output.status.success());
assert!(String::from_utf8(output.stderr)
.unwrap()
.contains("Could not find `set_validation_data` inherent"));
}
}
/// Test that ensures that `ValidationParams` and `MemoryOptimizedValidationParams`
/// are encoding/decoding.
#[test]
fn validation_params_and_memory_optimized_validation_params_encode_and_decode() {
const BLOCK_DATA: &[u8] = &[1, 2, 3, 4, 5];
const PARENT_HEAD: &[u8] = &[1, 3, 4, 5, 6, 7, 9];
let validation_params = ValidationParams {
block_data: BlockData(BLOCK_DATA.encode()),
parent_head: HeadData(PARENT_HEAD.encode()),
relay_parent_number: 1,
relay_parent_storage_root: Hash::random(),
};
let encoded = validation_params.encode();
let decoded = MemoryOptimizedValidationParams::decode_all(&mut &encoded[..]).unwrap();
assert_eq!(decoded.relay_parent_number, validation_params.relay_parent_number);
assert_eq!(decoded.relay_parent_storage_root, validation_params.relay_parent_storage_root);
assert_eq!(decoded.block_data, validation_params.block_data.0);
assert_eq!(decoded.parent_head, validation_params.parent_head.0);
let encoded = decoded.encode();
let decoded = ValidationParams::decode_all(&mut &encoded[..]).unwrap();
assert_eq!(decoded, validation_params);
}