mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 08:41:07 +00:00
Ensure inherent are first (#8173)
* impl * fix tests * impl in execute_block * fix tests * add a test in frame-executive * fix some panic warning * use trait to get call from extrinsic * remove unused * fix test * fix testing * fix tests * return index of extrinsic on error * fix test * Update primitives/inherents/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * address comments rename trait, and refactor * refactor + doc improvment * fix tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
6679b88af8
commit
a4ed9bb9b2
Generated
+1
@@ -1779,6 +1779,7 @@ dependencies = [
|
|||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
"sp-inherents",
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
|
|||||||
@@ -392,6 +392,10 @@ impl<T: Config> ProvideInherent for Module<T> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
|
matches!(call, Call::set_uncles(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pallet-indices = { version = "3.0.0", path = "../indices" }
|
|||||||
pallet-balances = { version = "3.0.0", path = "../balances" }
|
pallet-balances = { version = "3.0.0", path = "../balances" }
|
||||||
pallet-transaction-payment = { version = "3.0.0", path = "../transaction-payment" }
|
pallet-transaction-payment = { version = "3.0.0", path = "../transaction-payment" }
|
||||||
sp-version = { version = "3.0.0", path = "../../primitives/version" }
|
sp-version = { version = "3.0.0", path = "../../primitives/version" }
|
||||||
|
sp-inherents = { version = "3.0.0", path = "../../primitives/inherents" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -119,7 +119,10 @@
|
|||||||
use sp_std::{prelude::*, marker::PhantomData};
|
use sp_std::{prelude::*, marker::PhantomData};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
weights::{GetDispatchInfo, DispatchInfo, DispatchClass},
|
weights::{GetDispatchInfo, DispatchInfo, DispatchClass},
|
||||||
traits::{OnInitialize, OnIdle, OnFinalize, OnRuntimeUpgrade, OffchainWorker, ExecuteBlock},
|
traits::{
|
||||||
|
OnInitialize, OnIdle, OnFinalize, OnRuntimeUpgrade, OffchainWorker, ExecuteBlock,
|
||||||
|
EnsureInherentsAreFirst,
|
||||||
|
},
|
||||||
dispatch::PostDispatchInfo,
|
dispatch::PostDispatchInfo,
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
@@ -153,7 +156,7 @@ pub struct Executive<System, Block, Context, UnsignedValidator, AllPallets, OnRu
|
|||||||
);
|
);
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
System: frame_system::Config,
|
System: frame_system::Config + EnsureInherentsAreFirst<Block>,
|
||||||
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
|
||||||
Context: Default,
|
Context: Default,
|
||||||
UnsignedValidator,
|
UnsignedValidator,
|
||||||
@@ -181,7 +184,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
System: frame_system::Config,
|
System: frame_system::Config + EnsureInherentsAreFirst<Block>,
|
||||||
Block: traits::Block<Header = System::Header, Hash = System::Hash>,
|
Block: traits::Block<Header = System::Header, Hash = System::Hash>,
|
||||||
Context: Default,
|
Context: Default,
|
||||||
UnsignedValidator,
|
UnsignedValidator,
|
||||||
@@ -311,6 +314,10 @@ where
|
|||||||
&& <frame_system::Pallet<System>>::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(),
|
&& <frame_system::Pallet<System>>::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(),
|
||||||
"Parent hash should be valid.",
|
"Parent hash should be valid.",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Err(i) = System::ensure_inherents_are_first(block) {
|
||||||
|
panic!("Invalid inherent position for extrinsic at index {}", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Actually execute all transitions for `block`.
|
/// Actually execute all transitions for `block`.
|
||||||
@@ -543,7 +550,7 @@ mod tests {
|
|||||||
mod custom {
|
mod custom {
|
||||||
use frame_support::weights::{Weight, DispatchClass};
|
use frame_support::weights::{Weight, DispatchClass};
|
||||||
use sp_runtime::transaction_validity::{
|
use sp_runtime::transaction_validity::{
|
||||||
UnknownTransaction, TransactionSource, TransactionValidity
|
UnknownTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Config: frame_system::Config {}
|
pub trait Config: frame_system::Config {}
|
||||||
@@ -574,6 +581,11 @@ mod tests {
|
|||||||
frame_system::ensure_root(origin)?;
|
frame_system::ensure_root(origin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[weight = 0]
|
||||||
|
fn inherent_call(origin) {
|
||||||
|
let _ = frame_system::ensure_none(origin)?;
|
||||||
|
}
|
||||||
|
|
||||||
// module hooks.
|
// module hooks.
|
||||||
// one with block number arg and one without
|
// one with block number arg and one without
|
||||||
fn on_initialize(n: T::BlockNumber) -> Weight {
|
fn on_initialize(n: T::BlockNumber) -> Weight {
|
||||||
@@ -600,16 +612,29 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[weight = 0]
|
#[weight = 0]
|
||||||
fn calculate_storage_root(origin) {
|
fn calculate_storage_root(_origin) {
|
||||||
let root = sp_io::storage::root();
|
let root = sp_io::storage::root();
|
||||||
sp_io::storage::set("storage_root".as_bytes(), &root);
|
sp_io::storage::set("storage_root".as_bytes(), &root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Config> sp_inherents::ProvideInherent for Module<T> {
|
||||||
|
type Call = Call<T>;
|
||||||
|
type Error = sp_inherents::MakeFatalError<()>;
|
||||||
|
const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234";
|
||||||
|
fn create_inherent(_data: &sp_inherents::InherentData) -> Option<Self::Call> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
|
*call == Call::<T>::inherent_call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Config> sp_runtime::traits::ValidateUnsigned for Module<T> {
|
impl<T: Config> sp_runtime::traits::ValidateUnsigned for Module<T> {
|
||||||
type Call = Call<T>;
|
type Call = Call<T>;
|
||||||
|
|
||||||
|
// Inherent call is not validated as unsigned
|
||||||
fn validate_unsigned(
|
fn validate_unsigned(
|
||||||
_source: TransactionSource,
|
_source: TransactionSource,
|
||||||
call: &Self::Call,
|
call: &Self::Call,
|
||||||
@@ -618,6 +643,18 @@ mod tests {
|
|||||||
Call::allowed_unsigned(..) => Ok(Default::default()),
|
Call::allowed_unsigned(..) => Ok(Default::default()),
|
||||||
_ => UnknownTransaction::NoUnsignedValidator.into(),
|
_ => UnknownTransaction::NoUnsignedValidator.into(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherent call is accepted for being dispatched
|
||||||
|
fn pre_dispatch(
|
||||||
|
call: &Self::Call,
|
||||||
|
) -> Result<(), TransactionValidityError> {
|
||||||
|
match call {
|
||||||
|
Call::allowed_unsigned(..) => Ok(()),
|
||||||
|
Call::inherent_call(..) => Ok(()),
|
||||||
|
_ => Err(UnknownTransaction::NoUnsignedValidator.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,7 +667,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||||
Custom: custom::{Pallet, Call, ValidateUnsigned},
|
Custom: custom::{Pallet, Call, ValidateUnsigned, Inherent},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -718,12 +755,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
type TestXt = sp_runtime::testing::TestXt<Call, SignedExtra>;
|
type TestXt = sp_runtime::testing::TestXt<Call, SignedExtra>;
|
||||||
type TestBlock = Block<TestXt>;
|
type TestBlock = Block<TestXt>;
|
||||||
type TestUncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<
|
type TestUncheckedExtrinsic = TestXt;
|
||||||
<Runtime as frame_system::Config>::AccountId,
|
|
||||||
<Runtime as frame_system::Config>::Call,
|
|
||||||
(),
|
|
||||||
SignedExtra,
|
|
||||||
>;
|
|
||||||
|
|
||||||
// Will contain `true` when the custom runtime logic was called.
|
// Will contain `true` when the custom runtime logic was called.
|
||||||
const CUSTOM_ON_RUNTIME_KEY: &[u8] = &*b":custom:on_runtime";
|
const CUSTOM_ON_RUNTIME_KEY: &[u8] = &*b":custom:on_runtime";
|
||||||
@@ -1227,4 +1259,57 @@ mod tests {
|
|||||||
Executive::execute_block(Block::new(header, vec![xt]));
|
Executive::execute_block(Block::new(header, vec![xt]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Invalid inherent position for extrinsic at index 1")]
|
||||||
|
fn invalid_inherent_position_fail() {
|
||||||
|
let xt1 = TestXt::new(Call::Balances(BalancesCall::transfer(33, 0)), sign_extra(1, 0, 0));
|
||||||
|
let xt2 = TestXt::new(Call::Custom(custom::Call::inherent_call()), None);
|
||||||
|
|
||||||
|
let header = new_test_ext(1).execute_with(|| {
|
||||||
|
// Let's build some fake block.
|
||||||
|
Executive::initialize_block(&Header::new(
|
||||||
|
1,
|
||||||
|
H256::default(),
|
||||||
|
H256::default(),
|
||||||
|
[69u8; 32].into(),
|
||||||
|
Digest::default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap();
|
||||||
|
Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap();
|
||||||
|
|
||||||
|
Executive::finalize_block()
|
||||||
|
});
|
||||||
|
|
||||||
|
new_test_ext(1).execute_with(|| {
|
||||||
|
Executive::execute_block(Block::new(header, vec![xt1, xt2]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid_inherents_position_works() {
|
||||||
|
let xt1 = TestXt::new(Call::Custom(custom::Call::inherent_call()), None);
|
||||||
|
let xt2 = TestXt::new(Call::Balances(BalancesCall::transfer(33, 0)), sign_extra(1, 0, 0));
|
||||||
|
|
||||||
|
let header = new_test_ext(1).execute_with(|| {
|
||||||
|
// Let's build some fake block.
|
||||||
|
Executive::initialize_block(&Header::new(
|
||||||
|
1,
|
||||||
|
H256::default(),
|
||||||
|
H256::default(),
|
||||||
|
[69u8; 32].into(),
|
||||||
|
Digest::default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap();
|
||||||
|
Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap();
|
||||||
|
|
||||||
|
Executive::finalize_block()
|
||||||
|
});
|
||||||
|
|
||||||
|
new_test_ext(1).execute_with(|| {
|
||||||
|
Executive::execute_block(Block::new(header, vec![xt1, xt2]));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
|||||||
let metadata = decl_runtime_metadata(&name, pallets.iter(), &scrate, &unchecked_extrinsic);
|
let metadata = decl_runtime_metadata(&name, pallets.iter(), &scrate, &unchecked_extrinsic);
|
||||||
let outer_config = decl_outer_config(&name, pallets.iter(), &scrate);
|
let outer_config = decl_outer_config(&name, pallets.iter(), &scrate);
|
||||||
let inherent = decl_outer_inherent(
|
let inherent = decl_outer_inherent(
|
||||||
|
&name,
|
||||||
&block,
|
&block,
|
||||||
&unchecked_extrinsic,
|
&unchecked_extrinsic,
|
||||||
pallets.iter(),
|
pallets.iter(),
|
||||||
@@ -235,6 +236,7 @@ fn decl_validate_unsigned<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decl_outer_inherent<'a>(
|
fn decl_outer_inherent<'a>(
|
||||||
|
runtime: &'a Ident,
|
||||||
block: &'a syn::TypePath,
|
block: &'a syn::TypePath,
|
||||||
unchecked_extrinsic: &'a syn::TypePath,
|
unchecked_extrinsic: &'a syn::TypePath,
|
||||||
pallet_declarations: impl Iterator<Item = &'a Pallet>,
|
pallet_declarations: impl Iterator<Item = &'a Pallet>,
|
||||||
@@ -251,7 +253,8 @@ fn decl_outer_inherent<'a>(
|
|||||||
#scrate::impl_outer_inherent!(
|
#scrate::impl_outer_inherent!(
|
||||||
impl Inherents where
|
impl Inherents where
|
||||||
Block = #block,
|
Block = #block,
|
||||||
UncheckedExtrinsic = #unchecked_extrinsic
|
UncheckedExtrinsic = #unchecked_extrinsic,
|
||||||
|
Runtime = #runtime,
|
||||||
{
|
{
|
||||||
#(#pallets_tokens)*
|
#(#pallets_tokens)*
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ pub use crate::sp_std::vec::Vec;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::sp_runtime::traits::{Block as BlockT, Extrinsic};
|
pub use crate::sp_runtime::traits::{Block as BlockT, Extrinsic};
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use sp_inherents::{InherentData, ProvideInherent, CheckInherentsResult, IsFatalError};
|
pub use sp_inherents::{
|
||||||
|
InherentData, ProvideInherent, CheckInherentsResult, IsFatalError, InherentIdentifier,
|
||||||
|
MakeFatalError,
|
||||||
|
};
|
||||||
|
|
||||||
/// Implement the outer inherent.
|
/// Implement the outer inherent.
|
||||||
/// All given modules need to implement `ProvideInherent`.
|
/// All given modules need to implement `ProvideInherent`.
|
||||||
@@ -30,7 +32,11 @@ pub use sp_inherents::{InherentData, ProvideInherent, CheckInherentsResult, IsFa
|
|||||||
///
|
///
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// impl_outer_inherent! {
|
/// impl_outer_inherent! {
|
||||||
/// impl Inherents where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic {
|
/// impl Inherents where
|
||||||
|
/// Block = Block,
|
||||||
|
/// UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
|
/// Runtime = Runtime,
|
||||||
|
/// {
|
||||||
/// timestamp,
|
/// timestamp,
|
||||||
/// consensus,
|
/// consensus,
|
||||||
/// aura,
|
/// aura,
|
||||||
@@ -42,7 +48,8 @@ macro_rules! impl_outer_inherent {
|
|||||||
(
|
(
|
||||||
impl Inherents where
|
impl Inherents where
|
||||||
Block = $block:ident,
|
Block = $block:ident,
|
||||||
UncheckedExtrinsic = $uncheckedextrinsic:ident
|
UncheckedExtrinsic = $uncheckedextrinsic:ident,
|
||||||
|
Runtime = $runtime:ident,
|
||||||
{
|
{
|
||||||
$( $module:ident, )*
|
$( $module:ident, )*
|
||||||
}
|
}
|
||||||
@@ -56,16 +63,19 @@ macro_rules! impl_outer_inherent {
|
|||||||
impl InherentDataExt for $crate::inherent::InherentData {
|
impl InherentDataExt for $crate::inherent::InherentData {
|
||||||
fn create_extrinsics(&self) ->
|
fn create_extrinsics(&self) ->
|
||||||
$crate::inherent::Vec<<$block as $crate::inherent::BlockT>::Extrinsic> {
|
$crate::inherent::Vec<<$block as $crate::inherent::BlockT>::Extrinsic> {
|
||||||
use $crate::inherent::{ProvideInherent, Extrinsic};
|
use $crate::inherent::ProvideInherent;
|
||||||
|
|
||||||
let mut inherents = Vec::new();
|
let mut inherents = Vec::new();
|
||||||
|
|
||||||
$(
|
$(
|
||||||
if let Some(inherent) = $module::create_inherent(self) {
|
if let Some(inherent) = $module::create_inherent(self) {
|
||||||
inherents.push($uncheckedextrinsic::new(
|
let inherent = <$uncheckedextrinsic as $crate::inherent::Extrinsic>::new(
|
||||||
inherent.into(),
|
inherent.into(),
|
||||||
None,
|
None,
|
||||||
).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return `Some`; qed"));
|
).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \
|
||||||
|
`Some`; qed");
|
||||||
|
|
||||||
|
inherents.push(inherent);
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
@@ -74,41 +84,64 @@ macro_rules! impl_outer_inherent {
|
|||||||
|
|
||||||
fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult {
|
fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult {
|
||||||
use $crate::inherent::{ProvideInherent, IsFatalError};
|
use $crate::inherent::{ProvideInherent, IsFatalError};
|
||||||
use $crate::traits::IsSubType;
|
use $crate::traits::{IsSubType, ExtrinsicCall};
|
||||||
use $crate::sp_runtime::traits::Block as _;
|
use $crate::sp_runtime::traits::Block as _;
|
||||||
|
|
||||||
let mut result = $crate::inherent::CheckInherentsResult::new();
|
let mut result = $crate::inherent::CheckInherentsResult::new();
|
||||||
|
|
||||||
for xt in block.extrinsics() {
|
for xt in block.extrinsics() {
|
||||||
|
// Inherents are before any other extrinsics.
|
||||||
|
// And signed extrinsics are not inherents.
|
||||||
if $crate::inherent::Extrinsic::is_signed(xt).unwrap_or(false) {
|
if $crate::inherent::Extrinsic::is_signed(xt).unwrap_or(false) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut is_inherent = false;
|
||||||
|
|
||||||
$({
|
$({
|
||||||
if let Some(call) = IsSubType::<_>::is_sub_type(&xt.function) {
|
let call = <$uncheckedextrinsic as ExtrinsicCall>::call(xt);
|
||||||
if let Err(e) = $module::check_inherent(call, self) {
|
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
|
||||||
result.put_error(
|
if $module::is_inherent(call) {
|
||||||
$module::INHERENT_IDENTIFIER, &e
|
is_inherent = true;
|
||||||
).expect("There is only one fatal error; qed");
|
if let Err(e) = $module::check_inherent(call, self) {
|
||||||
if e.is_fatal_error() {
|
result.put_error(
|
||||||
return result
|
$module::INHERENT_IDENTIFIER, &e
|
||||||
|
).expect("There is only one fatal error; qed");
|
||||||
|
if e.is_fatal_error() {
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
|
// Inherents are before any other extrinsics.
|
||||||
|
// No module marked it as inherent thus it is not.
|
||||||
|
if !is_inherent {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
match $module::is_inherent_required(self) {
|
match $module::is_inherent_required(self) {
|
||||||
Ok(Some(e)) => {
|
Ok(Some(e)) => {
|
||||||
let found = block.extrinsics().iter().any(|xt| {
|
let found = block.extrinsics().iter().any(|xt| {
|
||||||
if $crate::inherent::Extrinsic::is_signed(xt).unwrap_or(false) {
|
let is_signed = $crate::inherent::Extrinsic::is_signed(xt)
|
||||||
return false
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_signed {
|
||||||
|
let call = <
|
||||||
|
$uncheckedextrinsic as ExtrinsicCall
|
||||||
|
>::call(xt);
|
||||||
|
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
|
||||||
|
$module::is_inherent(&call)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Signed extrinsics are not inherents.
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
let call: Option<&<$module as ProvideInherent>::Call> =
|
|
||||||
xt.function.is_sub_type();
|
|
||||||
|
|
||||||
call.is_some()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
@@ -135,6 +168,46 @@ macro_rules! impl_outer_inherent {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl $crate::traits::EnsureInherentsAreFirst<$block> for $runtime {
|
||||||
|
fn ensure_inherents_are_first(block: &$block) -> Result<(), u32> {
|
||||||
|
use $crate::inherent::ProvideInherent;
|
||||||
|
use $crate::traits::{IsSubType, ExtrinsicCall};
|
||||||
|
use $crate::sp_runtime::traits::Block as _;
|
||||||
|
|
||||||
|
let mut first_signed_observed = false;
|
||||||
|
|
||||||
|
for (i, xt) in block.extrinsics().iter().enumerate() {
|
||||||
|
let is_signed = $crate::inherent::Extrinsic::is_signed(xt).unwrap_or(false);
|
||||||
|
|
||||||
|
let is_inherent = if is_signed {
|
||||||
|
// Signed extrinsics are not inherents.
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
let mut is_inherent = false;
|
||||||
|
$({
|
||||||
|
let call = <$uncheckedextrinsic as ExtrinsicCall>::call(xt);
|
||||||
|
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
|
||||||
|
if $module::is_inherent(&call) {
|
||||||
|
is_inherent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
is_inherent
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_inherent {
|
||||||
|
first_signed_observed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if first_signed_observed && is_inherent {
|
||||||
|
return Err(i as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +215,6 @@ macro_rules! impl_outer_inherent {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use sp_runtime::{traits, testing::{Header, self}};
|
use sp_runtime::{traits, testing::{Header, self}};
|
||||||
use crate::traits::IsSubType;
|
|
||||||
|
|
||||||
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
||||||
enum Call {
|
enum Call {
|
||||||
@@ -162,7 +234,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsSubType<CallTest> for Call {
|
impl crate::traits::IsSubType<CallTest> for Call {
|
||||||
fn is_sub_type(&self) -> Option<&CallTest> {
|
fn is_sub_type(&self) -> Option<&CallTest> {
|
||||||
match self {
|
match self {
|
||||||
Self::Test(test) => Some(test),
|
Self::Test(test) => Some(test),
|
||||||
@@ -171,7 +243,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsSubType<CallTest2> for Call {
|
impl crate::traits::IsSubType<CallTest2> for Call {
|
||||||
fn is_sub_type(&self) -> Option<&CallTest2> {
|
fn is_sub_type(&self) -> Option<&CallTest2> {
|
||||||
match self {
|
match self {
|
||||||
Self::Test2(test) => Some(test),
|
Self::Test2(test) => Some(test),
|
||||||
@@ -182,13 +254,13 @@ mod tests {
|
|||||||
|
|
||||||
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
||||||
enum CallTest {
|
enum CallTest {
|
||||||
Something,
|
OptionalInherent(bool),
|
||||||
SomethingElse,
|
NotInherent,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
||||||
enum CallTest2 {
|
enum CallTest2 {
|
||||||
Something,
|
RequiredInherent,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleTest;
|
struct ModuleTest;
|
||||||
@@ -198,15 +270,20 @@ mod tests {
|
|||||||
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1235";
|
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1235";
|
||||||
|
|
||||||
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
|
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
|
||||||
Some(CallTest::Something)
|
Some(CallTest::OptionalInherent(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_inherent(call: &Self::Call, _: &InherentData) -> Result<(), Self::Error> {
|
fn check_inherent(call: &Self::Call, _: &InherentData) -> Result<(), Self::Error> {
|
||||||
match call {
|
match call {
|
||||||
CallTest::Something => Ok(()),
|
CallTest::OptionalInherent(true) => Ok(()),
|
||||||
CallTest::SomethingElse => Err(().into()),
|
CallTest::OptionalInherent(false) => Err(().into()),
|
||||||
|
_ => unreachable!("other calls are not inherents"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
|
matches!(call, CallTest::OptionalInherent(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleTest2;
|
struct ModuleTest2;
|
||||||
@@ -216,18 +293,23 @@ mod tests {
|
|||||||
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1234";
|
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1234";
|
||||||
|
|
||||||
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
|
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
|
||||||
Some(CallTest2::Something)
|
Some(CallTest2::RequiredInherent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_inherent_required(_: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
|
fn is_inherent_required(_: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
|
||||||
Ok(Some(().into()))
|
Ok(Some(().into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
|
matches!(call, CallTest2::RequiredInherent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Block = testing::Block<Extrinsic>;
|
type Block = testing::Block<Extrinsic>;
|
||||||
|
|
||||||
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
|
||||||
struct Extrinsic {
|
struct Extrinsic {
|
||||||
|
signed: bool,
|
||||||
function: Call,
|
function: Call,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,15 +317,34 @@ mod tests {
|
|||||||
type Call = Call;
|
type Call = Call;
|
||||||
type SignaturePayload = ();
|
type SignaturePayload = ();
|
||||||
|
|
||||||
fn new(function: Call, _: Option<()>) -> Option<Self> {
|
fn new(function: Call, signed_data: Option<()>) -> Option<Self> {
|
||||||
Some(Self { function })
|
Some(Self {
|
||||||
|
function,
|
||||||
|
signed: signed_data.is_some(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_signed(&self) -> Option<bool> {
|
||||||
|
Some(self.signed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::traits::ExtrinsicCall for Extrinsic {
|
||||||
|
fn call(&self) -> &Self::Call {
|
||||||
|
&self.function
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parity_util_mem::malloc_size_of_is_0!(Extrinsic);
|
parity_util_mem::malloc_size_of_is_0!(Extrinsic);
|
||||||
|
|
||||||
|
struct Runtime;
|
||||||
|
|
||||||
impl_outer_inherent! {
|
impl_outer_inherent! {
|
||||||
impl Inherents where Block = Block, UncheckedExtrinsic = Extrinsic {
|
impl Inherents where
|
||||||
|
Block = Block,
|
||||||
|
UncheckedExtrinsic = Extrinsic,
|
||||||
|
Runtime = Runtime,
|
||||||
|
{
|
||||||
ModuleTest,
|
ModuleTest,
|
||||||
ModuleTest2,
|
ModuleTest2,
|
||||||
}
|
}
|
||||||
@@ -254,8 +355,8 @@ mod tests {
|
|||||||
let inherents = InherentData::new().create_extrinsics();
|
let inherents = InherentData::new().create_extrinsics();
|
||||||
|
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Extrinsic { function: Call::Test(CallTest::Something) },
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false },
|
||||||
Extrinsic { function: Call::Test2(CallTest2::Something) },
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
];
|
];
|
||||||
assert_eq!(expected, inherents);
|
assert_eq!(expected, inherents);
|
||||||
}
|
}
|
||||||
@@ -265,8 +366,8 @@ mod tests {
|
|||||||
let block = Block::new(
|
let block = Block::new(
|
||||||
Header::new_from_number(1),
|
Header::new_from_number(1),
|
||||||
vec![
|
vec![
|
||||||
Extrinsic { function: Call::Test2(CallTest2::Something) },
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
Extrinsic { function: Call::Test(CallTest::Something) },
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false },
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -275,8 +376,8 @@ mod tests {
|
|||||||
let block = Block::new(
|
let block = Block::new(
|
||||||
Header::new_from_number(1),
|
Header::new_from_number(1),
|
||||||
vec![
|
vec![
|
||||||
Extrinsic { function: Call::Test2(CallTest2::Something) },
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
Extrinsic { function: Call::Test(CallTest::SomethingElse) },
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(false)), signed: false },
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -287,9 +388,84 @@ mod tests {
|
|||||||
fn required_inherents_enforced() {
|
fn required_inherents_enforced() {
|
||||||
let block = Block::new(
|
let block = Block::new(
|
||||||
Header::new_from_number(1),
|
Header::new_from_number(1),
|
||||||
vec![Extrinsic { function: Call::Test(CallTest::Something) }],
|
vec![
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false }
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(InherentData::new().check_extrinsics(&block).fatal_error());
|
assert!(InherentData::new().check_extrinsics(&block).fatal_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_are_not_inherent() {
|
||||||
|
let block = Block::new(
|
||||||
|
Header::new_from_number(1),
|
||||||
|
vec![
|
||||||
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
|
// NOTE: checking this call would fail, but it is not checked as it is not an
|
||||||
|
// inherent, because it is signed.
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(false)), signed: true },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(InherentData::new().check_extrinsics(&block).ok());
|
||||||
|
|
||||||
|
let block = Block::new(
|
||||||
|
Header::new_from_number(1),
|
||||||
|
vec![
|
||||||
|
// NOTE: this is not considered an inherent, thus block is failing because of
|
||||||
|
// missing required inherent.
|
||||||
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: true },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
InherentData::new().check_extrinsics(&block).into_errors().collect::<Vec<_>>(),
|
||||||
|
vec![(*b"test1234", vec![])],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inherent_first_works() {
|
||||||
|
use crate::traits::EnsureInherentsAreFirst;
|
||||||
|
let block = Block::new(
|
||||||
|
Header::new_from_number(1),
|
||||||
|
vec![
|
||||||
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false },
|
||||||
|
Extrinsic { function: Call::Test(CallTest::NotInherent), signed: false },
|
||||||
|
Extrinsic { function: Call::Test(CallTest::NotInherent), signed: false },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(Runtime::ensure_inherents_are_first(&block).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inherent_cannot_be_placed_after_non_inherent() {
|
||||||
|
use crate::traits::EnsureInherentsAreFirst;
|
||||||
|
let block = Block::new(
|
||||||
|
Header::new_from_number(1),
|
||||||
|
vec![
|
||||||
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
|
Extrinsic { function: Call::Test(CallTest::NotInherent), signed: false },
|
||||||
|
// This inherent is placed after non inherent: invalid
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(Runtime::ensure_inherents_are_first(&block).err().unwrap(), 2);
|
||||||
|
|
||||||
|
let block = Block::new(
|
||||||
|
Header::new_from_number(1),
|
||||||
|
vec![
|
||||||
|
Extrinsic { function: Call::Test2(CallTest2::RequiredInherent), signed: false },
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: true },
|
||||||
|
// This inherent is placed after non inherent: invalid
|
||||||
|
Extrinsic { function: Call::Test(CallTest::OptionalInherent(true)), signed: false },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(Runtime::ensure_inherents_are_first(&block).err().unwrap(), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1939,6 +1939,10 @@ pub mod pallet_prelude {
|
|||||||
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
/// unimplemented!();
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Regular rust code needed for implementing ProvideInherent trait
|
/// // Regular rust code needed for implementing ProvideInherent trait
|
||||||
@@ -2066,6 +2070,10 @@ pub mod pallet_prelude {
|
|||||||
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
/// unimplemented!();
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Regular rust code needed for implementing ProvideInherent trait
|
/// // Regular rust code needed for implementing ProvideInherent trait
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ pub use filter::{
|
|||||||
mod misc;
|
mod misc;
|
||||||
pub use misc::{
|
pub use misc::{
|
||||||
Len, Get, GetDefault, HandleLifetime, TryDrop, Time, UnixTime, IsType, IsSubType, ExecuteBlock,
|
Len, Get, GetDefault, HandleLifetime, TryDrop, Time, UnixTime, IsType, IsSubType, ExecuteBlock,
|
||||||
SameOrOther, OnNewAccount, OnKilledAccount, OffchainWorker, GetBacking, Backing,
|
SameOrOther, OnNewAccount, OnKilledAccount, OffchainWorker, GetBacking, Backing, ExtrinsicCall,
|
||||||
|
EnsureInherentsAreFirst,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod stored_map;
|
mod stored_map;
|
||||||
|
|||||||
@@ -284,3 +284,40 @@ pub trait GetBacking {
|
|||||||
/// implicit motion. `None` if it does not.
|
/// implicit motion. `None` if it does not.
|
||||||
fn get_backing(&self) -> Option<Backing>;
|
fn get_backing(&self) -> Option<Backing>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A trait to ensure the inherent are before non-inherent in a block.
|
||||||
|
///
|
||||||
|
/// This is typically implemented on runtime, through `construct_runtime!`.
|
||||||
|
pub trait EnsureInherentsAreFirst<Block> {
|
||||||
|
/// Ensure the position of inherent is correct, i.e. they are before non-inherents.
|
||||||
|
///
|
||||||
|
/// On error return the index of the inherent with invalid position (counting from 0).
|
||||||
|
fn ensure_inherents_are_first(block: &Block) -> Result<(), u32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extrinsic on which we can get access to call.
|
||||||
|
pub trait ExtrinsicCall: sp_runtime::traits::Extrinsic {
|
||||||
|
/// Get the call of the extrinsic.
|
||||||
|
fn call(&self) -> &Self::Call;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl<Call, Extra> ExtrinsicCall for sp_runtime::testing::TestXt<Call, Extra> where
|
||||||
|
Call: codec::Codec + Sync + Send,
|
||||||
|
{
|
||||||
|
fn call(&self) -> &Self::Call {
|
||||||
|
&self.call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Address, Call, Signature, Extra> ExtrinsicCall
|
||||||
|
for sp_runtime::generic::UncheckedExtrinsic<Address, Call, Signature, Extra>
|
||||||
|
where
|
||||||
|
Extra: sp_runtime::traits::SignedExtension,
|
||||||
|
{
|
||||||
|
fn call(&self) -> &Self::Call {
|
||||||
|
&self.function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,6 +122,10 @@ mod module1 {
|
|||||||
fn check_inherent(_: &Self::Call, _: &InherentData) -> std::result::Result<(), Self::Error> {
|
fn check_inherent(_: &Self::Call, _: &InherentData) -> std::result::Result<(), Self::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +186,10 @@ mod module2 {
|
|||||||
fn check_inherent(_call: &Self::Call, _data: &InherentData) -> std::result::Result<(), Self::Error> {
|
fn check_inherent(_call: &Self::Call, _data: &InherentData) -> std::result::Result<(), Self::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -288,6 +288,10 @@ pub mod pallet {
|
|||||||
T::AccountId::from(SomeType6); // Test for where clause
|
T::AccountId::from(SomeType6); // Test for where clause
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
|
#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ pub mod pallet {
|
|||||||
fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
|
#[derive(codec::Encode, sp_runtime::RuntimeDebug)]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
error[E0046]: not all trait items implemented, missing: `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`
|
error[E0046]: not all trait items implemented, missing: `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`, `is_inherent`
|
||||||
--> $DIR/inherent_check_inner_span.rs:19:2
|
--> $DIR/inherent_check_inner_span.rs:19:2
|
||||||
|
|
|
|
||||||
19 | impl<T: Config> ProvideInherent for Pallet<T> {}
|
19 | impl<T: Config> ProvideInherent for Pallet<T> {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent` in implementation
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Call`, `Error`, `INHERENT_IDENTIFIER`, `create_inherent`, `is_inherent` in implementation
|
||||||
|
|
|
|
||||||
= help: implement the missing item: `type Call = Type;`
|
= help: implement the missing item: `type Call = Type;`
|
||||||
= help: implement the missing item: `type Error = Type;`
|
= help: implement the missing item: `type Error = Type;`
|
||||||
= help: implement the missing item: `const INHERENT_IDENTIFIER: [u8; 8] = value;`
|
= help: implement the missing item: `const INHERENT_IDENTIFIER: [u8; 8] = value;`
|
||||||
= help: implement the missing item: `fn create_inherent(_: &InherentData) -> std::option::Option<<Self as ProvideInherent>::Call> { todo!() }`
|
= help: implement the missing item: `fn create_inherent(_: &InherentData) -> std::option::Option<<Self as ProvideInherent>::Call> { todo!() }`
|
||||||
|
= help: implement the missing item: `fn is_inherent(_: &<Self as ProvideInherent>::Call) -> bool { todo!() }`
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ impl<T: Trait> sp_inherents::ProvideInherent for Module<T> {
|
|||||||
fn check_inherent(_: &Self::Call, _: &sp_inherents::InherentData) -> std::result::Result<(), Self::Error> {
|
fn check_inherent(_: &Self::Call, _: &sp_inherents::InherentData) -> std::result::Result<(), Self::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(_call: &Self::Call) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -241,6 +241,10 @@ pub mod pallet {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
|
matches!(call, Call::set(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -423,8 +423,10 @@ pub trait ProvideInherent {
|
|||||||
///
|
///
|
||||||
/// - `Err(_)` indicates that this function failed and further operations should be aborted.
|
/// - `Err(_)` indicates that this function failed and further operations should be aborted.
|
||||||
///
|
///
|
||||||
/// CAUTION: This check has a bug when used in pallets that also provide unsigned transactions.
|
/// NOTE: If inherent is required then the runtime asserts that the block contains at least
|
||||||
/// See <https://github.com/paritytech/substrate/issues/6243> for details.
|
/// one inherent for which:
|
||||||
|
/// * type is [`Self::Call`],
|
||||||
|
/// * [`Self::is_inherent`] returns true.
|
||||||
fn is_inherent_required(_: &InherentData) -> Result<Option<Self::Error>, Self::Error> { Ok(None) }
|
fn is_inherent_required(_: &InherentData) -> Result<Option<Self::Error>, Self::Error> { Ok(None) }
|
||||||
|
|
||||||
/// Check whether the given inherent is valid. Checking the inherent is optional and can be
|
/// Check whether the given inherent is valid. Checking the inherent is optional and can be
|
||||||
@@ -433,9 +435,24 @@ pub trait ProvideInherent {
|
|||||||
/// When checking an inherent, the first parameter represents the inherent that is actually
|
/// When checking an inherent, the first parameter represents the inherent that is actually
|
||||||
/// included in the block by its author. Whereas the second parameter represents the inherent
|
/// included in the block by its author. Whereas the second parameter represents the inherent
|
||||||
/// data that the verifying node calculates.
|
/// data that the verifying node calculates.
|
||||||
|
///
|
||||||
|
/// NOTE: A block can contains multiple inherent.
|
||||||
fn check_inherent(_: &Self::Call, _: &InherentData) -> Result<(), Self::Error> {
|
fn check_inherent(_: &Self::Call, _: &InherentData) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return whether the call is an inherent call.
|
||||||
|
///
|
||||||
|
/// NOTE: Signed extrinsics are not inherent, but signed extrinsic with the given call variant
|
||||||
|
/// can be dispatched.
|
||||||
|
///
|
||||||
|
/// # Warning
|
||||||
|
///
|
||||||
|
/// In FRAME, inherent are enforced to be before other extrinsics, for this reason,
|
||||||
|
/// pallets with unsigned transactions **must ensure** that no unsigned transaction call
|
||||||
|
/// is an inherent call, when implementing `ValidateUnsigned::validate_unsigned`.
|
||||||
|
/// Otherwise block producer can produce invalid blocks by including them after non inherent.
|
||||||
|
fn is_inherent(call: &Self::Call) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -303,6 +303,14 @@ impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Call, Extra> traits::ExtrinsicMetadata for TestXt<Call, Extra> where
|
||||||
|
Call: Codec + Sync + Send,
|
||||||
|
Extra: SignedExtension<AccountId=u64, Call=Call>,
|
||||||
|
{
|
||||||
|
type SignedExtensions = Extra;
|
||||||
|
const VERSION: u8 = 0u8;
|
||||||
|
}
|
||||||
|
|
||||||
impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
|
impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
|
||||||
Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable<Origin=Origin>,
|
Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable<Origin=Origin>,
|
||||||
Extra: SignedExtension<AccountId=u64, Call=Call>,
|
Extra: SignedExtension<AccountId=u64, Call=Call>,
|
||||||
|
|||||||
Reference in New Issue
Block a user