use crate::construct_runtime::Pallet;
use proc_macro2::TokenStream;
use quote::quote;
use std::str::FromStr;
use syn::{Ident, TypePath};
pub fn expand_outer_inherent(
runtime: &Ident,
block: &TypePath,
unchecked_extrinsic: &TypePath,
pallet_decls: &[Pallet],
scrate: &TokenStream,
) -> TokenStream {
let mut pallet_names = Vec::new();
let mut pallet_attrs = Vec::new();
let mut query_inherent_part_macros = Vec::new();
for pallet_decl in pallet_decls {
if pallet_decl.exists_part("Inherent") {
let name = &pallet_decl.name;
let path = &pallet_decl.path;
let attr = pallet_decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| {
let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original()))
.expect("was successfully parsed before; qed");
quote! {
#acc
#attr
}
});
pallet_names.push(name);
pallet_attrs.push(attr);
query_inherent_part_macros.push(quote! {
#path::__substrate_inherent_check::is_inherent_part_defined!(#name);
});
}
}
quote! {
#( #query_inherent_part_macros )*
trait InherentDataExt {
fn create_extrinsics(&self) ->
#scrate::inherent::Vec<<#block as #scrate::inherent::BlockT>::Extrinsic>;
fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult;
}
impl InherentDataExt for #scrate::inherent::InherentData {
fn create_extrinsics(&self) ->
#scrate::inherent::Vec<<#block as #scrate::inherent::BlockT>::Extrinsic>
{
use #scrate::inherent::ProvideInherent;
let mut inherents = Vec::new();
#(
#pallet_attrs
if let Some(inherent) = #pallet_names::create_inherent(self) {
let inherent = <#unchecked_extrinsic as #scrate::inherent::Extrinsic>::new(
inherent.into(),
None,
).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \
`Some`; qed");
inherents.push(inherent);
}
)*
inherents
}
fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult {
use #scrate::inherent::{ProvideInherent, IsFatalError};
use #scrate::traits::{IsSubType, ExtrinsicCall};
use #scrate::sp_runtime::traits::Block as _;
let mut result = #scrate::inherent::CheckInherentsResult::new();
for xt in block.extrinsics() {
if #scrate::inherent::Extrinsic::is_signed(xt).unwrap_or(false) {
break
}
let mut is_inherent = false;
#(
#pallet_attrs
{
let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt);
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
if #pallet_names::is_inherent(call) {
is_inherent = true;
if let Err(e) = #pallet_names::check_inherent(call, self) {
result.put_error(
#pallet_names::INHERENT_IDENTIFIER, &e
).expect("There is only one fatal error; qed");
if e.is_fatal_error() {
return result;
}
}
}
}
}
)*
if !is_inherent {
break
}
}
#(
#pallet_attrs
match #pallet_names::is_inherent_required(self) {
Ok(Some(e)) => {
let found = block.extrinsics().iter().any(|xt| {
let is_signed = #scrate::inherent::Extrinsic::is_signed(xt)
.unwrap_or(false);
if !is_signed {
let call = <
#unchecked_extrinsic as ExtrinsicCall
>::call(xt);
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
#pallet_names::is_inherent(&call)
} else {
false
}
} else {
false
}
});
if !found {
result.put_error(
#pallet_names::INHERENT_IDENTIFIER, &e
).expect("There is only one fatal error; qed");
if e.is_fatal_error() {
return result;
}
}
},
Ok(None) => (),
Err(e) => {
result.put_error(
#pallet_names::INHERENT_IDENTIFIER, &e
).expect("There is only one fatal error; qed");
if e.is_fatal_error() {
return result;
}
},
}
)*
result
}
}
impl #scrate::traits::EnsureInherentsAreFirst<#block> for #runtime {
fn ensure_inherents_are_first(block: &#block) -> Result<(), u32> {
use #scrate::inherent::ProvideInherent;
use #scrate::traits::{IsSubType, ExtrinsicCall};
use #scrate::sp_runtime::traits::Block as _;
let mut first_signed_observed = false;
for (i, xt) in block.extrinsics().iter().enumerate() {
let is_signed = #scrate::inherent::Extrinsic::is_signed(xt).unwrap_or(false);
let is_inherent = if is_signed {
false
} else {
let mut is_inherent = false;
#(
#pallet_attrs
{
let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt);
if let Some(call) = IsSubType::<_>::is_sub_type(call) {
if #pallet_names::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(())
}
}
}
}