Don't require module name in inherents (#6576)

* Start

* Cleanup `construct_runtime!`

* Add tests

* Fix after merge

* Update the docs
This commit is contained in:
Bastian Köcher
2020-07-06 12:29:17 +02:00
committed by GitHub
parent 2019f70768
commit ad2e832289
15 changed files with 279 additions and 161 deletions
+159 -25
View File
@@ -31,19 +31,20 @@ pub use sp_inherents::{InherentData, ProvideInherent, CheckInherentsResult, IsFa
/// ```nocompile
/// impl_outer_inherent! {
/// impl Inherents where Block = Block, UncheckedExtrinsic = UncheckedExtrinsic {
/// timestamp: Timestamp,
/// consensus: Consensus,
/// /// Aura module using the `Timestamp` call.
/// aura: Timestamp,
/// timestamp,
/// consensus,
/// aura,
/// }
/// }
/// ```
#[macro_export]
macro_rules! impl_outer_inherent {
(
impl Inherents where Block = $block:ident, UncheckedExtrinsic = $uncheckedextrinsic:ident
impl Inherents where
Block = $block:ident,
UncheckedExtrinsic = $uncheckedextrinsic:ident
{
$( $module:ident: $call:ident, )*
$( $module:ident, )*
}
) => {
trait InherentDataExt {
@@ -55,15 +56,14 @@ macro_rules! impl_outer_inherent {
impl InherentDataExt for $crate::inherent::InherentData {
fn create_extrinsics(&self) ->
$crate::inherent::Vec<<$block as $crate::inherent::BlockT>::Extrinsic> {
use $crate::inherent::ProvideInherent;
use $crate::inherent::Extrinsic;
use $crate::inherent::{ProvideInherent, Extrinsic};
let mut inherents = Vec::new();
$(
if let Some(inherent) = $module::create_inherent(self) {
inherents.push($uncheckedextrinsic::new(
Call::$call(inherent),
inherent.into(),
None,
).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return `Some`; qed"));
}
@@ -74,6 +74,7 @@ macro_rules! impl_outer_inherent {
fn check_extrinsics(&self, block: &$block) -> $crate::inherent::CheckInherentsResult {
use $crate::inherent::{ProvideInherent, IsFatalError};
use $crate::dispatch::IsSubType;
let mut result = $crate::inherent::CheckInherentsResult::new();
for xt in block.extrinsics() {
@@ -81,21 +82,18 @@ macro_rules! impl_outer_inherent {
break
}
$(
match xt.function {
Call::$call(ref call) => {
if let Err(e) = $module::check_inherent(call, self) {
result.put_error(
$module::INHERENT_IDENTIFIER, &e
).expect("There is only one fatal error; qed");
if e.is_fatal_error() {
return result
}
$({
if let Some(call) = IsSubType::<_>::is_sub_type(&xt.function) {
if let Err(e) = $module::check_inherent(call, self) {
result.put_error(
$module::INHERENT_IDENTIFIER, &e
).expect("There is only one fatal error; qed");
if e.is_fatal_error() {
return result
}
}
_ => {},
}
)*
})*
}
$(
@@ -106,10 +104,10 @@ macro_rules! impl_outer_inherent {
return false
}
match xt.function {
Call::$call(_) => true,
_ => false,
}
let call: Option<&<$module as ProvideInherent>::Call> =
xt.function.is_sub_type();
call.is_some()
});
if !found {
@@ -138,3 +136,139 @@ macro_rules! impl_outer_inherent {
}
};
}
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::{traits, testing::{Header, self}};
use crate::dispatch::IsSubType;
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
enum Call {
Test(CallTest),
Test2(CallTest2),
}
impl From<CallTest> for Call {
fn from(call: CallTest) -> Self {
Self::Test(call)
}
}
impl From<CallTest2> for Call {
fn from(call: CallTest2) -> Self {
Self::Test2(call)
}
}
impl IsSubType<CallTest> for Call {
fn is_sub_type(&self) -> Option<&CallTest> {
match self {
Self::Test(test) => Some(test),
_ => None,
}
}
}
impl IsSubType<CallTest2> for Call {
fn is_sub_type(&self) -> Option<&CallTest2> {
match self {
Self::Test2(test) => Some(test),
_ => None,
}
}
}
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
enum CallTest {
Something,
SomethingElse,
}
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
enum CallTest2 {
Something,
}
struct ModuleTest;
impl ProvideInherent for ModuleTest {
type Call = CallTest;
type Error = sp_inherents::MakeFatalError<()>;
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1235";
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
Some(CallTest::Something)
}
fn check_inherent(call: &Self::Call, _: &InherentData) -> Result<(), Self::Error> {
match call {
CallTest::Something => Ok(()),
CallTest::SomethingElse => Err(().into()),
}
}
}
struct ModuleTest2;
impl ProvideInherent for ModuleTest2 {
type Call = CallTest2;
type Error = sp_inherents::MakeFatalError<()>;
const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"test1234";
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
Some(CallTest2::Something)
}
}
type Block = testing::Block<Extrinsic>;
#[derive(codec::Encode, codec::Decode, Clone, PartialEq, Eq, Debug, serde::Serialize)]
struct Extrinsic {
function: Call,
}
impl traits::Extrinsic for Extrinsic {
type Call = Call;
type SignaturePayload = ();
fn new(function: Call, _: Option<()>) -> Option<Self> {
Some(Self { function })
}
}
parity_util_mem::malloc_size_of_is_0!(Extrinsic);
impl_outer_inherent! {
impl Inherents where Block = Block, UncheckedExtrinsic = Extrinsic {
ModuleTest,
ModuleTest2,
}
}
#[test]
fn create_inherents_works() {
let inherents = InherentData::new().create_extrinsics();
let expected = vec![
Extrinsic { function: Call::Test(CallTest::Something) },
Extrinsic { function: Call::Test2(CallTest2::Something) },
];
assert_eq!(expected, inherents);
}
#[test]
fn check_inherents_works() {
let block = Block::new(
Header::new_from_number(1),
vec![Extrinsic { function: Call::Test(CallTest::Something) }],
);
assert!(InherentData::new().check_extrinsics(&block).ok());
let block = Block::new(
Header::new_from_number(1),
vec![Extrinsic { function: Call::Test(CallTest::SomethingElse) }],
);
assert!(InherentData::new().check_extrinsics(&block).fatal_error());
}
}