sp_api_proc_macro/
impl_runtime_apis.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{
19	common::API_VERSION_ATTRIBUTE,
20	utils::{
21		extract_block_type_from_trait_path, extract_impl_trait,
22		extract_parameter_names_types_and_borrows, generate_crate_access,
23		generate_runtime_mod_name_for_trait, parse_runtime_api_version, prefix_function_with_trait,
24		versioned_trait_name, AllowSelfRefInParameters, RequireQualifiedTraitPath,
25	},
26};
27
28use proc_macro2::{Span, TokenStream};
29
30use quote::quote;
31
32use syn::{
33	fold::{self, Fold},
34	parenthesized,
35	parse::{Error, Parse, ParseStream, Result},
36	parse_macro_input, parse_quote,
37	spanned::Spanned,
38	Attribute, Ident, ImplItem, ItemImpl, LitInt, LitStr, Path, Signature, Type, TypePath,
39};
40
41use std::collections::HashMap;
42
43/// The structure used for parsing the runtime api implementations.
44struct RuntimeApiImpls {
45	impls: Vec<ItemImpl>,
46}
47
48impl Parse for RuntimeApiImpls {
49	fn parse(input: ParseStream) -> Result<Self> {
50		let mut impls = Vec::new();
51
52		while !input.is_empty() {
53			impls.push(ItemImpl::parse(input)?);
54		}
55
56		if impls.is_empty() {
57			Err(Error::new(Span::call_site(), "No api implementation given!"))
58		} else {
59			Ok(Self { impls })
60		}
61	}
62}
63
64/// Generates the call to the implementation of the requested function.
65/// The generated code includes decoding of the input arguments and encoding of the output.
66fn generate_impl_call(
67	signature: &Signature,
68	runtime: &Type,
69	input: &Ident,
70	impl_trait: &Path,
71	api_version: &ApiVersion,
72) -> Result<TokenStream> {
73	let params =
74		extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
75
76	let c = generate_crate_access();
77	let fn_name = &signature.ident;
78	let fn_name_str = fn_name.to_string();
79	let pnames = params.iter().map(|v| &v.0);
80	let pnames2 = params.iter().map(|v| &v.0);
81	let ptypes = params.iter().map(|v| &v.1);
82	let pborrow = params.iter().map(|v| &v.2);
83
84	let decode_params = if params.is_empty() {
85		quote!(
86			if !#input.is_empty() {
87				panic!(
88					"Bad input data provided to {}: expected no parameters, but input buffer is not empty.",
89					#fn_name_str
90				);
91			}
92		)
93	} else {
94		let let_binding = if params.len() == 1 {
95			quote! {
96				let #( #pnames )* : #( #ptypes )*
97			}
98		} else {
99			quote! {
100				let ( #( #pnames ),* ) : ( #( #ptypes ),* )
101			}
102		};
103
104		quote!(
105			#let_binding =
106				match #c::DecodeLimit::decode_all_with_depth_limit(
107					#c::MAX_EXTRINSIC_DEPTH,
108					&mut #input,
109				) {
110					Ok(res) => res,
111					Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
112				};
113		)
114	};
115
116	let fn_calls = if let Some(feature_gated) = &api_version.feature_gated {
117		let pnames = pnames2;
118		let pnames2 = pnames.clone();
119		let pborrow2 = pborrow.clone();
120
121		let feature_name = &feature_gated.0;
122		let impl_trait_fg = extend_with_api_version(impl_trait.clone(), Some(feature_gated.1));
123		let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
124
125		quote!(
126			#[cfg(feature = #feature_name)]
127			#[allow(deprecated)]
128			let r = <#runtime as #impl_trait_fg>::#fn_name(#( #pborrow #pnames ),*);
129
130			#[cfg(not(feature = #feature_name))]
131			#[allow(deprecated)]
132			let r = <#runtime as #impl_trait>::#fn_name(#( #pborrow2 #pnames2 ),*);
133
134			r
135		)
136	} else {
137		let pnames = pnames2;
138		let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
139
140		quote!(
141			#[allow(deprecated)]
142			<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames ),*)
143		)
144	};
145
146	Ok(quote!(
147		#decode_params
148
149		#fn_calls
150	))
151}
152
153/// Generate all the implementation calls for the given functions.
154fn generate_impl_calls(
155	impls: &[ItemImpl],
156	input: &Ident,
157) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
158	let mut impl_calls = Vec::new();
159
160	for impl_ in impls {
161		let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
162		let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
163		let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
164		let impl_trait_ident = &impl_trait_path
165			.segments
166			.last()
167			.ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
168			.ident;
169
170		for item in &impl_.items {
171			if let ImplItem::Fn(method) = item {
172				let impl_call = generate_impl_call(
173					&method.sig,
174					&impl_.self_ty,
175					input,
176					&impl_trait,
177					&trait_api_ver,
178				)?;
179				let mut attrs = filter_cfg_attrs(&impl_.attrs);
180
181				// Add any `#[cfg(feature = X)]` attributes of the method to result
182				attrs.extend(filter_cfg_attrs(&method.attrs));
183
184				impl_calls.push((
185					impl_trait_ident.clone(),
186					method.sig.ident.clone(),
187					impl_call,
188					attrs,
189				));
190			}
191		}
192	}
193
194	Ok(impl_calls)
195}
196
197/// Generate the dispatch function that is used in native to call into the runtime.
198fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
199	let data = Ident::new("_sp_api_input_data_", Span::call_site());
200	let c = generate_crate_access();
201	let impl_calls =
202		generate_impl_calls(impls, &data)?
203			.into_iter()
204			.map(|(trait_, fn_name, impl_, attrs)| {
205				let name = prefix_function_with_trait(&trait_, &fn_name);
206				quote!(
207					#( #attrs )*
208					#name => Some(#c::Encode::encode(&{ #impl_ })),
209				)
210			});
211
212	Ok(quote!(
213		#c::std_enabled! {
214			pub fn dispatch(method: &str, mut #data: &[u8]) -> Option<Vec<u8>> {
215				match method {
216					#( #impl_calls )*
217					_ => None,
218				}
219			}
220		}
221	))
222}
223
224/// Generate the interface functions that are used to call into the runtime in wasm.
225fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
226	let input = Ident::new("input", Span::call_site());
227	let c = generate_crate_access();
228
229	let impl_calls =
230		generate_impl_calls(impls, &input)?
231			.into_iter()
232			.map(|(trait_, fn_name, impl_, attrs)| {
233				let fn_name =
234					Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
235
236				quote!(
237					#c::std_disabled! {
238						#( #attrs )*
239						#[no_mangle]
240						#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))]
241						pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
242							let mut #input = if input_len == 0 {
243								&[0u8; 0]
244							} else {
245								unsafe {
246									::core::slice::from_raw_parts(input_data, input_len)
247								}
248							};
249
250							#c::init_runtime_logger();
251
252							let output = (move || { #impl_ })();
253							#c::to_substrate_wasm_fn_return_value(&output)
254						}
255					}
256				)
257			});
258
259	Ok(quote!( #( #impl_calls )* ))
260}
261
262fn generate_runtime_api_base_structures() -> Result<TokenStream> {
263	let crate_ = generate_crate_access();
264
265	Ok(quote!(
266		pub struct RuntimeApi {}
267		#crate_::std_enabled! {
268			/// Implements all runtime apis for the client side.
269			pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
270				call: &'static C,
271				transaction_depth: std::cell::RefCell<u16>,
272				changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor<Block>>>,
273				recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
274				call_context: #crate_::CallContext,
275				extensions: std::cell::RefCell<#crate_::Extensions>,
276				extensions_generated_for: std::cell::RefCell<std::option::Option<Block::Hash>>,
277			}
278
279			#[automatically_derived]
280			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
281				RuntimeApiImpl<Block, C>
282			{
283				fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
284					&self,
285					call: F,
286				) -> R where Self: Sized {
287					self.start_transaction();
288
289					*std::cell::RefCell::borrow_mut(&self.transaction_depth) += 1;
290					let res = call(self);
291					std::cell::RefCell::borrow_mut(&self.transaction_depth)
292						.checked_sub(1)
293						.expect("Transactions are opened and closed together; qed");
294
295					self.commit_or_rollback_transaction(
296						std::matches!(res, #crate_::TransactionOutcome::Commit(_))
297					);
298
299					res.into_inner()
300				}
301
302				fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
303					&self,
304					at: <Block as #crate_::BlockT>::Hash,
305				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
306					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
307					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
308				}
309
310				fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
311					&self,
312					at: <Block as #crate_::BlockT>::Hash,
313					pred: P,
314				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
315					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
316					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))
317				}
318
319				fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
320					&self,
321					at: <Block as #crate_::BlockT>::Hash,
322				) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
323					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
324					.map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID))
325				}
326
327				fn record_proof(&mut self) {
328					self.recorder = std::option::Option::Some(std::default::Default::default());
329				}
330
331				fn proof_recorder(&self) -> std::option::Option<#crate_::ProofRecorder<Block>> {
332					std::clone::Clone::clone(&self.recorder)
333				}
334
335				fn extract_proof(
336					&mut self,
337				) -> std::option::Option<#crate_::StorageProof> {
338					let recorder = std::option::Option::take(&mut self.recorder);
339					std::option::Option::map(recorder, |recorder| {
340						#crate_::ProofRecorder::<Block>::drain_storage_proof(recorder)
341					})
342				}
343
344				fn into_storage_changes<B: #crate_::StateBackend<#crate_::HashingFor<Block>>>(
345					&self,
346					backend: &B,
347					parent_hash: Block::Hash,
348				) -> ::core::result::Result<
349					#crate_::StorageChanges<Block>,
350				String
351					> where Self: Sized {
352						let state_version = #crate_::CallApiAt::<Block>::runtime_version_at(self.call, std::clone::Clone::clone(&parent_hash))
353							.map(|v| #crate_::RuntimeVersion::state_version(&v))
354							.map_err(|e| format!("Failed to get state version: {}", e))?;
355
356						#crate_::OverlayedChanges::drain_storage_changes(
357							&mut std::cell::RefCell::borrow_mut(&self.changes),
358							backend,
359							state_version,
360						)
361					}
362
363				fn set_call_context(&mut self, call_context: #crate_::CallContext) {
364					self.call_context = call_context;
365				}
366
367				fn register_extension<E: #crate_::Extension>(&mut self, extension: E) {
368					std::cell::RefCell::borrow_mut(&self.extensions).register(extension);
369				}
370			}
371
372			#[automatically_derived]
373			impl<Block: #crate_::BlockT, C> #crate_::ConstructRuntimeApi<Block, C>
374				for RuntimeApi
375			where
376				C: #crate_::CallApiAt<Block> + 'static,
377			{
378				type RuntimeApi = RuntimeApiImpl<Block, C>;
379
380				fn construct_runtime_api<'a>(
381					call: &'a C,
382				) -> #crate_::ApiRef<'a, Self::RuntimeApi> {
383					RuntimeApiImpl {
384						call: unsafe { std::mem::transmute(call) },
385						transaction_depth: 0.into(),
386						changes: std::default::Default::default(),
387						recorder: std::default::Default::default(),
388						call_context: #crate_::CallContext::Offchain,
389						extensions: std::default::Default::default(),
390						extensions_generated_for: std::default::Default::default(),
391					}.into()
392				}
393			}
394
395			#[automatically_derived]
396			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> RuntimeApiImpl<Block, C> {
397				fn commit_or_rollback_transaction(&self, commit: bool) {
398					let proof = "\
399					We only close a transaction when we opened one ourself.
400					Other parts of the runtime that make use of transactions (state-machine)
401					also balance their transactions. The runtime cannot close client initiated
402					transactions; qed";
403
404					let res = if commit {
405						let res = if let Some(recorder) = &self.recorder {
406							#crate_::ProofRecorder::<Block>::commit_transaction(&recorder)
407						} else {
408							Ok(())
409						};
410
411						let res2 = #crate_::OverlayedChanges::commit_transaction(
412							&mut std::cell::RefCell::borrow_mut(&self.changes)
413						);
414
415						// Will panic on an `Err` below, however we should call commit
416						// on the recorder and the changes together.
417						std::result::Result::and(res, std::result::Result::map_err(res2, drop))
418					} else {
419						let res = if let Some(recorder) = &self.recorder {
420							#crate_::ProofRecorder::<Block>::rollback_transaction(&recorder)
421						} else {
422							Ok(())
423						};
424
425						let res2 = #crate_::OverlayedChanges::rollback_transaction(
426							&mut std::cell::RefCell::borrow_mut(&self.changes)
427						);
428
429						// Will panic on an `Err` below, however we should call commit
430						// on the recorder and the changes together.
431						std::result::Result::and(res, std::result::Result::map_err(res2, drop))
432					};
433
434					std::result::Result::expect(res, proof);
435				}
436
437				fn start_transaction(&self) {
438					#crate_::OverlayedChanges::start_transaction(
439						&mut std::cell::RefCell::borrow_mut(&self.changes)
440					);
441					if let Some(recorder) = &self.recorder {
442						#crate_::ProofRecorder::<Block>::start_transaction(&recorder);
443					}
444				}
445			}
446		}
447	))
448}
449
450/// Extend the given trait path with module that contains the declaration of the trait for the
451/// runtime.
452fn extend_with_runtime_decl_path(mut trait_: Path) -> Path {
453	let runtime = {
454		let trait_name = &trait_
455			.segments
456			.last()
457			.as_ref()
458			.expect("Trait path should always contain at least one item; qed")
459			.ident;
460
461		generate_runtime_mod_name_for_trait(trait_name)
462	};
463
464	let pos = trait_.segments.len() - 1;
465	trait_.segments.insert(pos, runtime.into());
466	trait_
467}
468
469fn extend_with_api_version(mut trait_: Path, version: Option<u64>) -> Path {
470	let version = if let Some(v) = version {
471		v
472	} else {
473		// nothing to do
474		return trait_;
475	};
476
477	let trait_name = &mut trait_
478		.segments
479		.last_mut()
480		.expect("Trait path should always contain at least one item; qed")
481		.ident;
482	*trait_name = versioned_trait_name(trait_name, version);
483
484	trait_
485}
486
487/// Adds a feature guard to `attributes`.
488///
489/// Depending on `enable`, the feature guard either enables ('feature = "something"`) or disables
490/// (`not(feature = "something")`).
491fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
492	let attr = match enable {
493		true => parse_quote!(#[cfg(feature = #feature_name)]),
494		false => parse_quote!(#[cfg(not(feature = #feature_name))]),
495	};
496	attrs.push(attr);
497}
498
499/// Generates the implementations of the apis for the runtime.
500fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
501	let mut impls_prepared = Vec::new();
502
503	// We put `runtime` before each trait to get the trait that is intended for the runtime and
504	// we put the `RuntimeBlock` as first argument for the trait generics.
505	for impl_ in impls.iter() {
506		let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
507
508		let mut impl_ = impl_.clone();
509		impl_.attrs = filter_cfg_attrs(&impl_.attrs);
510
511		let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone();
512		let trait_ = extend_with_runtime_decl_path(trait_);
513		// If the trait api contains feature gated version - there are staging methods in it. Handle
514		// them explicitly here by adding staging implementation with `#cfg(feature = ...)` and
515		// stable implementation with `#[cfg(not(feature = ...))]`.
516		if let Some(feature_gated) = trait_api_ver.feature_gated {
517			let mut feature_gated_impl = impl_.clone();
518			add_feature_guard(&mut feature_gated_impl.attrs, &feature_gated.0, true);
519			feature_gated_impl.trait_.as_mut().unwrap().1 =
520				extend_with_api_version(trait_.clone(), Some(feature_gated.1));
521
522			impls_prepared.push(feature_gated_impl);
523
524			// Finally add `#[cfg(not(feature = ...))]` for the stable implementation (which is
525			// generated outside this if).
526			add_feature_guard(&mut impl_.attrs, &feature_gated.0, false);
527		}
528
529		// Generate stable trait implementation.
530		let trait_ = extend_with_api_version(trait_, trait_api_ver.custom);
531		impl_.trait_.as_mut().unwrap().1 = trait_;
532		impls_prepared.push(impl_);
533	}
534
535	Ok(quote!( #( #impls_prepared )* ))
536}
537
538/// Auxiliary data structure that is used to convert `impl Api for Runtime` to
539/// `impl Api for RuntimeApi`.
540/// This requires us to replace the runtime `Block` with the node `Block`,
541/// `impl Api for Runtime` with `impl Api for RuntimeApi` and replace the method implementations
542/// with code that calls into the runtime.
543struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
544	runtime_block: &'a TypePath,
545}
546
547impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
548	/// Process the given item implementation.
549	fn process(mut self, input: ItemImpl) -> ItemImpl {
550		let mut input = self.fold_item_impl(input);
551
552		let crate_ = generate_crate_access();
553
554		// Delete all functions, because all of them are default implemented by
555		// `decl_runtime_apis!`. We only need to implement the `__runtime_api_internal_call_api_at`
556		// function.
557		input.items.clear();
558		input.items.push(parse_quote! {
559			fn __runtime_api_internal_call_api_at(
560				&self,
561				at: <__SrApiBlock__ as #crate_::BlockT>::Hash,
562				params: std::vec::Vec<u8>,
563				fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
564			) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
565				// If we are not already in a transaction, we should create a new transaction
566				// and then commit/roll it back at the end!
567				let transaction_depth = *std::cell::RefCell::borrow(&self.transaction_depth);
568
569				if transaction_depth == 0 {
570					self.start_transaction();
571				}
572
573				let res = (|| {
574					let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at(
575						self.call,
576						at,
577					)?;
578
579					match &mut *std::cell::RefCell::borrow_mut(&self.extensions_generated_for) {
580						Some(generated_for) => {
581							if *generated_for != at {
582								return std::result::Result::Err(
583									#crate_::ApiError::UsingSameInstanceForDifferentBlocks
584								)
585							}
586						},
587						generated_for @ None => {
588							#crate_::CallApiAt::<__SrApiBlock__>::initialize_extensions(
589								self.call,
590								at,
591								&mut std::cell::RefCell::borrow_mut(&self.extensions),
592							)?;
593
594							*generated_for = Some(at);
595						}
596					}
597
598					let params = #crate_::CallApiAtParams {
599						at,
600						function: (*fn_name)(version),
601						arguments: params,
602						overlayed_changes: &self.changes,
603						call_context: self.call_context,
604						recorder: &self.recorder,
605						extensions: &self.extensions,
606					};
607
608					#crate_::CallApiAt::<__SrApiBlock__>::call_api_at(
609						self.call,
610						params,
611					)
612				})();
613
614				if transaction_depth == 0 {
615					self.commit_or_rollback_transaction(std::result::Result::is_ok(&res));
616				}
617
618				res
619			}
620		});
621
622		input
623	}
624}
625
626impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
627	fn fold_type_path(&mut self, input: TypePath) -> TypePath {
628		let new_ty_path =
629			if input == *self.runtime_block { parse_quote!(__SrApiBlock__) } else { input };
630
631		fold::fold_type_path(self, new_ty_path)
632	}
633
634	fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl {
635		let crate_ = generate_crate_access();
636
637		// Implement the trait for the `RuntimeApiImpl`
638		input.self_ty =
639			Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> ));
640
641		input.generics.params.push(parse_quote!(
642			__SrApiBlock__: #crate_::BlockT
643		));
644
645		input
646			.generics
647			.params
648			.push(parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SrApiBlock__> + 'static ));
649
650		let where_clause = input.generics.make_where_clause();
651
652		where_clause.predicates.push(parse_quote! {
653			RuntimeApiImplCall::StateBackend:
654				#crate_::StateBackend<#crate_::HashingFor<__SrApiBlock__>>
655		});
656
657		where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send });
658
659		input.attrs = filter_cfg_attrs(&input.attrs);
660
661		fold::fold_item_impl(self, input)
662	}
663}
664
665/// Generate the implementations of the runtime apis for the `RuntimeApi` type.
666fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream> {
667	let mut result = Vec::with_capacity(impls.len());
668
669	for impl_ in impls {
670		let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
671		let runtime_block = extract_block_type_from_trait_path(impl_trait_path)?;
672		let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone());
673		// remove the trait to get just the module path
674		runtime_mod_path.segments.pop();
675
676		let mut processed_impl =
677			ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone());
678
679		processed_impl.attrs.push(parse_quote!(#[automatically_derived]));
680
681		result.push(processed_impl);
682	}
683
684	let crate_ = generate_crate_access();
685
686	Ok(quote!( #crate_::std_enabled! { #( #result )* } ))
687}
688
689fn populate_runtime_api_versions(
690	result: &mut Vec<TokenStream>,
691	sections: &mut Vec<TokenStream>,
692	attrs: Vec<Attribute>,
693	id: Path,
694	version: TokenStream,
695	crate_access: &TokenStream,
696) {
697	result.push(quote!(
698			#( #attrs )*
699			(#id, #version)
700	));
701
702	sections.push(quote!(
703		#crate_access::std_disabled! {
704			#( #attrs )*
705			const _: () = {
706				// All sections with the same name are going to be merged by concatenation.
707				#[link_section = "runtime_apis"]
708				static SECTION_CONTENTS: [u8; 12] = #crate_access::serialize_runtime_api_info(#id, #version);
709			};
710		}
711	));
712}
713
714/// Generates `RUNTIME_API_VERSIONS` that holds all version information about the implemented
715/// runtime apis.
716fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
717	let mut result = Vec::<TokenStream>::with_capacity(impls.len());
718	let mut sections = Vec::<TokenStream>::with_capacity(impls.len());
719	let mut processed_traits = HashMap::new();
720
721	let c = generate_crate_access();
722
723	for impl_ in impls {
724		let versions = extract_api_version(&impl_.attrs, impl_.span())?;
725		let api_ver = versions.custom.map(|a| a as u32);
726
727		let mut path = extend_with_runtime_decl_path(
728			extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(),
729		);
730		// Remove the trait
731		let trait_ = path
732			.segments
733			.pop()
734			.expect("extract_impl_trait already checks that this is valid; qed")
735			.into_value()
736			.ident;
737
738		let span = trait_.span();
739		if let Some(other_span) = processed_traits.insert(trait_, span) {
740			let mut error = Error::new(
741				span,
742				"Two traits with the same name detected! \
743					The trait name is used to generate its ID. \
744					Please rename one trait at the declaration!",
745			);
746
747			error.combine(Error::new(other_span, "First trait implementation."));
748
749			return Err(error);
750		}
751
752		let id: Path = parse_quote!( #path ID );
753		let mut attrs = filter_cfg_attrs(&impl_.attrs);
754
755		// Handle API versioning
756		// If feature gated version is set - handle it first
757		if let Some(feature_gated) = versions.feature_gated {
758			let feature_gated_version = feature_gated.1 as u32;
759			// the attributes for the feature gated staging api
760			let mut feature_gated_attrs = attrs.clone();
761			add_feature_guard(&mut feature_gated_attrs, &feature_gated.0, true);
762			populate_runtime_api_versions(
763				&mut result,
764				&mut sections,
765				feature_gated_attrs,
766				id.clone(),
767				quote!( #feature_gated_version ),
768				&c,
769			);
770
771			// Add `#[cfg(not(feature ...))]` to the initial attributes. If the staging feature flag
772			// is not set we want to set the stable api version
773			add_feature_guard(&mut attrs, &feature_gated.0, false);
774		}
775
776		// Now add the stable api version to the versions list. If the api has got staging functions
777		// there might be a `#[cfg(not(feature ...))]` attribute attached to the stable version.
778		let base_api_version = quote!( #path VERSION );
779		let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version);
780		populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c);
781	}
782
783	Ok(quote!(
784		pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
785
786		#( #sections )*
787	))
788}
789
790/// The implementation of the `impl_runtime_apis!` macro.
791pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
792	// Parse all impl blocks
793	let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
794
795	impl_runtime_apis_impl_inner(&api_impls)
796		.unwrap_or_else(|e| e.to_compile_error())
797		.into()
798}
799
800fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
801	let dispatch_impl = generate_dispatch_function(api_impls)?;
802	let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
803	let base_runtime_api = generate_runtime_api_base_structures()?;
804	let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
805	let wasm_interface = generate_wasm_interface(api_impls)?;
806	let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
807
808	let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
809
810	let impl_ = quote!(
811		#base_runtime_api
812
813		#api_impls_for_runtime
814
815		#api_impls_for_runtime_api
816
817		#runtime_api_versions
818
819		#runtime_metadata
820
821		pub mod api {
822			use super::*;
823
824			#dispatch_impl
825
826			#wasm_interface
827		}
828	);
829
830	let impl_ = expander::Expander::new("impl_runtime_apis")
831		.dry(std::env::var("EXPAND_MACROS").is_err())
832		.verbose(true)
833		.write_to_out_dir(impl_)
834		.expect("Does not fail because of IO in OUT_DIR; qed");
835
836	Ok(impl_)
837}
838
839// Filters all attributes except the cfg ones.
840fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
841	attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect()
842}
843
844/// Parse feature flagged api_version.
845/// E.g. `#[cfg_attr(feature = "enable-staging-api", api_version(99))]`
846fn extract_cfg_api_version(attrs: &Vec<Attribute>, span: Span) -> Result<Option<(String, u64)>> {
847	let cfg_attrs = attrs.iter().filter(|a| a.path().is_ident("cfg_attr")).collect::<Vec<_>>();
848
849	let mut cfg_api_version_attr = Vec::new();
850	for cfg_attr in cfg_attrs {
851		let mut feature_name = None;
852		let mut api_version = None;
853		cfg_attr.parse_nested_meta(|m| {
854			if m.path.is_ident("feature") {
855				let a = m.value()?;
856				let b: LitStr = a.parse()?;
857				feature_name = Some(b.value());
858			} else if m.path.is_ident(API_VERSION_ATTRIBUTE) {
859				let content;
860				parenthesized!(content in m.input);
861				let ver: LitInt = content.parse()?;
862				api_version = Some(ver.base10_parse::<u64>()?);
863			}
864			Ok(())
865		})?;
866
867		// If there is a cfg attribute containing api_version - save if for processing
868		if let (Some(feature_name), Some(api_version)) = (feature_name, api_version) {
869			cfg_api_version_attr.push((feature_name, api_version, cfg_attr.span()));
870		}
871	}
872
873	if cfg_api_version_attr.len() > 1 {
874		let mut err = Error::new(span, format!("Found multiple feature gated api versions (cfg attribute with nested `{}` attribute). This is not supported.", API_VERSION_ATTRIBUTE));
875		for (_, _, attr_span) in cfg_api_version_attr {
876			err.combine(Error::new(attr_span, format!("`{}` found here", API_VERSION_ATTRIBUTE)));
877		}
878
879		return Err(err);
880	}
881
882	Ok(cfg_api_version_attr
883		.into_iter()
884		.next()
885		.map(|(feature, name, _)| (feature, name)))
886}
887
888/// Represents an API version.
889struct ApiVersion {
890	/// Corresponds to `#[api_version(X)]` attribute.
891	pub custom: Option<u64>,
892	/// Corresponds to `#[cfg_attr(feature = "enable-staging-api", api_version(99))]`
893	/// attribute. `String` is the feature name, `u64` the staging api version.
894	pub feature_gated: Option<(String, u64)>,
895}
896
897// Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors.
898// Returns:
899// - Err if the version is malformed
900// - `ApiVersion` on success. If a version is set or not is determined by the fields of `ApiVersion`
901fn extract_api_version(attrs: &Vec<Attribute>, span: Span) -> Result<ApiVersion> {
902	// First fetch all `API_VERSION_ATTRIBUTE` values (should be only one)
903	let api_ver = attrs
904		.iter()
905		.filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE))
906		.collect::<Vec<_>>();
907
908	if api_ver.len() > 1 {
909		return Err(Error::new(
910			span,
911			format!(
912				"Found multiple #[{}] attributes for an API implementation. \
913				Each runtime API can have only one version.",
914				API_VERSION_ATTRIBUTE
915			),
916		));
917	}
918
919	// Parse the runtime version if there exists one.
920	Ok(ApiVersion {
921		custom: api_ver.first().map(|v| parse_runtime_api_version(v)).transpose()?,
922		feature_gated: extract_cfg_api_version(attrs, span)?,
923	})
924}
925
926#[cfg(test)]
927mod tests {
928	use super::*;
929
930	#[test]
931	fn filter_non_cfg_attributes() {
932		let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
933		let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
934
935		let attrs = vec![
936			cfg_std.clone(),
937			parse_quote!(#[derive(Debug)]),
938			parse_quote!(#[test]),
939			cfg_benchmarks.clone(),
940			parse_quote!(#[allow(non_camel_case_types)]),
941		];
942
943		let filtered = filter_cfg_attrs(&attrs);
944		assert_eq!(filtered.len(), 2);
945		assert_eq!(cfg_std, filtered[0]);
946		assert_eq!(cfg_benchmarks, filtered[1]);
947	}
948}