cumulus_pallet_parachain_system_proc_macro/
lib.rs1use proc_macro2::Span;
18use proc_macro_crate::{crate_name, FoundCrate};
19use syn::{
20 parse::{Parse, ParseStream},
21 spanned::Spanned,
22 token, Error, Ident, Path,
23};
24
25mod keywords {
26 syn::custom_keyword!(Runtime);
27 syn::custom_keyword!(BlockExecutor);
28 syn::custom_keyword!(CheckInherents);
29}
30
31struct Input {
32 runtime: Path,
33 block_executor: Path,
34 check_inherents: Option<Path>,
35}
36
37impl Parse for Input {
38 fn parse(input: ParseStream) -> Result<Self, Error> {
39 let mut runtime = None;
40 let mut block_executor = None;
41 let mut check_inherents = None;
42
43 fn parse_inner<KW: Parse + Spanned>(
44 input: ParseStream,
45 result: &mut Option<Path>,
46 ) -> Result<(), Error> {
47 let kw = input.parse::<KW>()?;
48
49 if result.is_none() {
50 input.parse::<token::Eq>()?;
51 *result = Some(input.parse::<Path>()?);
52 if input.peek(token::Comma) {
53 input.parse::<token::Comma>()?;
54 }
55
56 Ok(())
57 } else {
58 Err(Error::new(kw.span(), "Is only allowed to be passed once"))
59 }
60 }
61
62 while !input.is_empty() || runtime.is_none() || block_executor.is_none() {
63 let lookahead = input.lookahead1();
64
65 if lookahead.peek(keywords::Runtime) {
66 parse_inner::<keywords::Runtime>(input, &mut runtime)?;
67 } else if lookahead.peek(keywords::BlockExecutor) {
68 parse_inner::<keywords::BlockExecutor>(input, &mut block_executor)?;
69 } else if lookahead.peek(keywords::CheckInherents) {
70 parse_inner::<keywords::CheckInherents>(input, &mut check_inherents)?;
71 } else {
72 return Err(lookahead.error())
73 }
74 }
75
76 Ok(Self {
77 runtime: runtime.expect("Everything is parsed before; qed"),
78 block_executor: block_executor.expect("Everything is parsed before; qed"),
79 check_inherents,
80 })
81 }
82}
83
84fn crate_() -> Result<Ident, Error> {
85 match crate_name("cumulus-pallet-parachain-system") {
86 Ok(FoundCrate::Itself) =>
87 Ok(syn::Ident::new("cumulus_pallet_parachain_system", Span::call_site())),
88 Ok(FoundCrate::Name(name)) => Ok(Ident::new(&name, Span::call_site())),
89 Err(e) => Err(Error::new(Span::call_site(), e)),
90 }
91}
92
93#[proc_macro]
94pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
95 let Input { runtime, block_executor, check_inherents } = match syn::parse(input) {
96 Ok(t) => t,
97 Err(e) => return e.into_compile_error().into(),
98 };
99
100 let crate_ = match crate_() {
101 Ok(c) => c,
102 Err(e) => return e.into_compile_error().into(),
103 };
104
105 let check_inherents = match check_inherents {
106 Some(_check_inherents) => {
107 quote::quote! { #_check_inherents }
108 },
109 None => {
110 quote::quote! {
111 #crate_::DummyCheckInherents<<#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock>
112 }
113 },
114 };
115
116 if cfg!(not(feature = "std")) {
117 quote::quote! {
118 #[doc(hidden)]
119 mod parachain_validate_block {
120 use super::*;
121
122 #[no_mangle]
123 unsafe fn validate_block(arguments: *mut u8, arguments_len: usize) -> u64 {
124 let args = #crate_::validate_block::Box::from_raw(
126 #crate_::validate_block::slice::from_raw_parts_mut(
127 arguments,
128 arguments_len,
129 )
130 );
131 let args = #crate_::validate_block::bytes::Bytes::from(args);
132
133 let params = #crate_::validate_block::decode_from_bytes::<
135 #crate_::validate_block::MemoryOptimizedValidationParams
136 >(args).expect("Invalid arguments to `validate_block`.");
137
138 let res = #crate_::validate_block::implementation::validate_block::<
139 <#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock,
140 #block_executor,
141 #runtime,
142 #check_inherents,
143 >(params);
144
145 #crate_::validate_block::polkadot_parachain_primitives::write_result(&res)
146 }
147 }
148 }
149 } else {
150 quote::quote!()
151 }
152 .into()
153}