Merge remote-tracking branch 'origin/master' into gav-xcm-v3

This commit is contained in:
Keith Yeung
2021-12-30 21:40:20 -08:00
198 changed files with 10258 additions and 6371 deletions
+37 -46
View File
@@ -33,7 +33,7 @@ use cumulus_primitives_core::{
OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender,
XcmpMessageHandler, XcmpMessageSource,
};
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData};
use frame_support::{
dispatch::{DispatchError, DispatchResult},
ensure,
@@ -46,7 +46,7 @@ use frame_system::{ensure_none, ensure_root};
use polkadot_parachain::primitives::RelayChainBlockNumber;
use relay_state_snapshot::MessagingStateSnapshot;
use sp_runtime::{
traits::{BlakeTwo256, Block as BlockT, BlockNumberProvider, Hash},
traits::{Block as BlockT, BlockNumberProvider, Hash},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
ValidTransaction,
@@ -236,8 +236,9 @@ pub mod pallet {
HrmpWatermark::<T>::kill();
UpwardMessages::<T>::kill();
HrmpOutboundMessages::<T>::kill();
CustomValidationHeadData::<T>::kill();
weight += T::DbWeight::get().writes(5);
weight += T::DbWeight::get().writes(6);
// Here, in `on_initialize` we must report the weight for both `on_initialize` and
// `on_finalize`.
@@ -567,6 +568,12 @@ pub mod pallet {
#[pallet::storage]
pub(super) type AuthorizedUpgrade<T: Config> = StorageValue<_, T::Hash>;
/// A custom head data that should be returned as result of `validate_block`.
///
/// See [`Pallet::set_custom_validation_head_data`] for more information.
#[pallet::storage]
pub(super) type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;
#[pallet::inherent]
impl<T: Config> ProvideInherent for Pallet<T> {
type Call = Call<T>;
@@ -609,7 +616,7 @@ pub mod pallet {
if let Ok(hash) = Self::validate_authorized_upgrade(code) {
return Ok(ValidTransaction {
priority: 100,
requires: vec![],
requires: Vec::new(),
provides: vec![hash.as_ref().to_vec()],
longevity: TransactionLongevity::max_value(),
propagate: true,
@@ -692,6 +699,9 @@ impl<T: Config> Pallet<T> {
/// import, this is a no-op.
///
/// # Panics
///
/// Panics while validating the `PoV` on the relay chain if the [`PersistedValidationData`]
/// passed by the block author was incorrect.
fn validate_validation_data(validation_data: &PersistedValidationData) {
validate_block::with_validation_params(|params| {
assert_eq!(
@@ -714,8 +724,10 @@ impl<T: Config> Pallet<T> {
/// Checks if the sequence of the messages is valid, dispatches them and communicates the
/// number of processed messages to the collator via a storage update.
///
/// **Panics** if it turns out that after processing all messages the Message Queue Chain
/// hash doesn't match the expected.
/// # Panics
///
/// If it turns out that after processing all messages the Message Queue Chain
/// hash doesn't match the expected.
fn process_inbound_downward_messages(
expected_dmq_mqc_head: relay_chain::Hash,
downward_messages: Vec<InboundDownwardMessage>,
@@ -738,7 +750,7 @@ impl<T: Config> Pallet<T> {
weight_used += T::DmpMessageHandler::handle_dmp_messages(message_iter, max_weight);
<LastDmqMqcHead<T>>::put(&dmq_head);
Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.0));
Self::deposit_event(Event::DownwardMessagesProcessed(weight_used, dmq_head.head()));
}
// After hashing each message in the message queue chain submitted by the collator, we
@@ -746,7 +758,7 @@ impl<T: Config> Pallet<T> {
//
// A mismatch means that at least some of the submitted messages were altered, omitted or
// added improperly.
assert_eq!(dmq_head.0, expected_dmq_mqc_head);
assert_eq!(dmq_head.head(), expected_dmq_mqc_head);
ProcessedDownwardMessages::<T>::put(dm_count);
@@ -907,6 +919,22 @@ impl<T: Config> Pallet<T> {
new_validation_code: NewValidationCode::<T>::get().map(Into::into),
}
}
/// Set a custom head data that should be returned as result of `validate_block`.
///
/// This will overwrite the head data that is returned as result of `validate_block` while
/// validating a `PoV` on the relay chain. Normally the head data that is being returned
/// by `validate_block` is the header of the block that is validated, thus it can be
/// enacted as the new best block. However, for features like forking it can be useful
/// to overwrite the head data with a custom header.
///
/// # Attention
///
/// This should only be used when you are sure what you are doing as this can brick
/// your Parachain.
pub fn set_custom_validation_head_data(head_data: Vec<u8>) {
CustomValidationHeadData::<T>::put(head_data);
}
}
pub struct ParachainSetCode<T>(sp_std::marker::PhantomData<T>);
@@ -917,43 +945,6 @@ impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
}
}
/// This struct provides ability to extend a message queue chain (MQC) and compute a new head.
///
/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's
/// possible to represent a sequence of messages using only a single hash.
///
/// A head for an empty chain is agreed to be a zero hash.
///
/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain
#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)]
struct MessageQueueChain(relay_chain::Hash);
impl MessageQueueChain {
fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self {
let prev_head = self.0;
self.0 = BlakeTwo256::hash_of(&(
prev_head,
horizontal_message.sent_at,
BlakeTwo256::hash_of(&horizontal_message.data),
));
self
}
fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self {
let prev_head = self.0;
self.0 = BlakeTwo256::hash_of(&(
prev_head,
downward_message.sent_at,
BlakeTwo256::hash_of(&downward_message.msg),
));
self
}
fn head(&self) -> relay_chain::Hash {
self.0
}
}
impl<T: Config> Pallet<T> {
pub fn send_upward_message(message: UpwardMessage) -> Result<u32, MessageSendError> {
// Check if the message fits into the relay-chain constraints.
@@ -1008,7 +999,7 @@ pub trait CheckInherents<Block: BlockT> {
) -> frame_support::inherent::CheckInherentsResult;
}
/// Implements [`BlockNumberProvider`] that returns relaychain block number fetched from
/// Implements [`BlockNumberProvider`] that returns relay chain block number fetched from
/// validation data.
/// NTOE: When validation data is not available (e.g. within on_initialize), 0 will be returned.
pub struct RelaychainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
+6 -1
View File
@@ -33,7 +33,10 @@ use frame_system::{InitKind, RawOrigin};
use hex_literal::hex;
use relay_chain::v1::HrmpChannelId;
use sp_core::H256;
use sp_runtime::{testing::Header, traits::IdentityLookup};
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
};
use sp_version::RuntimeVersion;
use std::cell::RefCell;
@@ -63,6 +66,7 @@ parameter_types! {
impl_version: 1,
apis: sp_version::create_apis_vec!([]),
transaction_version: 1,
state_version: 1,
};
pub const ParachainId: ParaId = ParaId::new(200);
pub const ReservedXcmpWeight: Weight = 0;
@@ -92,6 +96,7 @@ impl frame_system::Config for Test {
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ParachainSetCode<Self>;
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
impl Config for Test {
type Event = Event;
@@ -17,7 +17,7 @@
//! The actual implementation of the validate block functionality.
use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType};
use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT, NumberFor};
use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT};
use sp_io::KillStorageResult;
use sp_std::prelude::*;
@@ -26,13 +26,13 @@ use polkadot_parachain::primitives::{HeadData, ValidationParams, ValidationResul
use codec::{Decode, Encode};
use sp_core::storage::ChildInfo;
use sp_core::storage::{ChildInfo, StateVersion};
use sp_externalities::{set_and_run_with_externalities, Externalities};
use sp_trie::MemoryDB;
type TrieBackend<B> = sp_state_machine::TrieBackend<MemoryDB<HashFor<B>>, HashFor<B>>;
type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor<B>, NumberFor<B>, TrieBackend<B>>;
type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor<B>, TrieBackend<B>>;
fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> R {
sp_externalities::with_externalities(f).expect("Environmental externalities not set.")
@@ -68,7 +68,7 @@ where
// Uncompress
let mut db = MemoryDB::default();
let root = match sp_trie::decode_compact::<sp_trie::Layout<HashFor<B>>, _, _>(
let root = match sp_trie::decode_compact::<sp_trie::LayoutV1<HashFor<B>>, _, _>(
&mut db,
storage_proof.iter_compact_encoded_nodes(),
Some(parent_head.state_root()),
@@ -89,7 +89,6 @@ where
sp_io::storage::host_clear.replace_implementation(host_storage_clear),
sp_io::storage::host_root.replace_implementation(host_storage_root),
sp_io::storage::host_clear_prefix.replace_implementation(host_storage_clear_prefix),
sp_io::storage::host_changes_root.replace_implementation(host_storage_changes_root),
sp_io::storage::host_append.replace_implementation(host_storage_append),
sp_io::storage::host_next_key.replace_implementation(host_storage_next_key),
sp_io::storage::host_start_transaction
@@ -162,6 +161,13 @@ where
let horizontal_messages = crate::HrmpOutboundMessages::<PSC>::get();
let hrmp_watermark = crate::HrmpWatermark::<PSC>::get();
let head_data =
if let Some(custom_head_data) = crate::CustomValidationHeadData::<PSC>::get() {
HeadData(custom_head_data)
} else {
head_data
};
ValidationResult {
head_data,
new_validation_code: new_validation_code.map(Into::into),
@@ -215,8 +221,8 @@ fn host_storage_clear(key: &[u8]) {
with_externalities(|ext| ext.place_storage(key.to_vec(), None))
}
fn host_storage_root() -> Vec<u8> {
with_externalities(|ext| ext.storage_root())
fn host_storage_root(version: StateVersion) -> Vec<u8> {
with_externalities(|ext| ext.storage_root(version))
}
fn host_storage_clear_prefix(prefix: &[u8], limit: Option<u32>) -> KillStorageResult {
@@ -229,10 +235,6 @@ fn host_storage_clear_prefix(prefix: &[u8], limit: Option<u32>) -> KillStorageRe
})
}
fn host_storage_changes_root(parent_hash: &[u8]) -> Option<Vec<u8>> {
with_externalities(|ext| ext.storage_changes_root(parent_hash).ok().flatten())
}
fn host_storage_append(key: &[u8], value: Vec<u8>) {
with_externalities(|ext| ext.storage_append(key.to_vec(), value))
}
@@ -325,9 +327,9 @@ fn host_default_child_storage_clear_prefix(
})
}
fn host_default_child_storage_root(storage_key: &[u8]) -> Vec<u8> {
fn host_default_child_storage_root(storage_key: &[u8], version: StateVersion) -> Vec<u8> {
let child_info = ChildInfo::new_default(storage_key);
with_externalities(|ext| ext.child_storage_root(&child_info))
with_externalities(|ext| ext.child_storage_root(&child_info, version))
}
fn host_default_child_storage_next_key(storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
@@ -17,7 +17,8 @@
use codec::{Decode, Encode};
use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
use cumulus_test_client::{
runtime::{Block, Hash, Header, UncheckedExtrinsic, WASM_BINARY},
generate_extrinsic,
runtime::{Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY},
transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData,
InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams,
};
@@ -26,11 +27,11 @@ use sp_keyring::AccountKeyring::*;
use sp_runtime::{generic::BlockId, traits::Header as HeaderT};
use std::{env, process::Command};
fn call_validate_block(
fn call_validate_block_encoded_header(
parent_head: Header,
block_data: ParachainBlockData<Block>,
relay_parent_storage_root: Hash,
) -> cumulus_test_client::ExecutorResult<Header> {
) -> cumulus_test_client::ExecutorResult<Vec<u8>> {
cumulus_test_client::validate_block(
ValidationParams {
block_data: BlockData(block_data.encode()),
@@ -40,7 +41,16 @@ fn call_validate_block(
},
&WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"),
)
.map(|v| Header::decode(&mut &v.head_data.0[..]).expect("Decodes `Header`."))
.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) {
@@ -92,7 +102,7 @@ fn validate_block_no_extra_extrinsics() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } =
build_block_with_witness(&client, vec![], parent_head.clone(), Default::default());
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
let header = block.header().clone();
let res_header =
@@ -126,6 +136,43 @@ fn validate_block_with_extra_extrinsics() {
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();
@@ -133,7 +180,7 @@ fn validate_block_invalid_parent_hash() {
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![], parent_head.clone(), Default::default());
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));
@@ -159,7 +206,7 @@ fn validate_block_fails_on_invalid_validation_data() {
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, .. } =
build_block_with_witness(&client, vec![], parent_head.clone(), Default::default());
build_block_with_witness(&client, Vec::new(), parent_head.clone(), Default::default());
call_validate_block(parent_head, block, Hash::random()).unwrap_err();
} else {
@@ -184,7 +231,7 @@ fn check_inherent_fails_on_validate_block_as_expected() {
let TestBlockData { block, validation_data } = build_block_with_witness(
&client,
vec![],
Vec::new(),
parent_head.clone(),
RelayStateSproofBuilder { current_slot: 1337.into(), ..Default::default() },
);