referrerpolicy=no-referrer-when-downgrade

cumulus_pallet_parachain_system_proc_macro/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use 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					// We convert the `arguments` into a boxed slice and then into `Bytes`.
125					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					// Then we decode from these bytes the `MemoryOptimizedValidationParams`.
134					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}