mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 00:31:07 +00:00
Merge remote-tracking branch 'origin/master' into gav-xcm-v3
This commit is contained in:
@@ -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>);
|
||||
|
||||
@@ -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() },
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user