referrerpolicy=no-referrer-when-downgrade

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::utils::{
19	extract_api_version, extract_block_type_from_trait_path, extract_impl_trait,
20	extract_parameter_names_types_and_borrows, generate_crate_access,
21	generate_runtime_mod_name_for_trait, prefix_function_with_trait, versioned_trait_name,
22	AllowSelfRefInParameters, ApiVersion, RequireQualifiedTraitPath,
23};
24
25use proc_macro2::{Span, TokenStream};
26
27use quote::quote;
28
29use syn::{
30	fold::{self, Fold},
31	parse::{Error, Parse, ParseStream, Result},
32	parse_macro_input, parse_quote,
33	spanned::Spanned,
34	visit_mut::{self, VisitMut},
35	Attribute, Ident, ImplItem, ItemImpl, Path, Signature, Type, TypePath,
36};
37
38use std::collections::HashMap;
39
40/// The structure used for parsing the runtime api implementations.
41struct RuntimeApiImpls {
42	impls: Vec<ItemImpl>,
43}
44
45impl Parse for RuntimeApiImpls {
46	fn parse(input: ParseStream) -> Result<Self> {
47		let mut impls = Vec::new();
48
49		while !input.is_empty() {
50			impls.push(ItemImpl::parse(input)?);
51		}
52
53		if impls.is_empty() {
54			Err(Error::new(Span::call_site(), "No api implementation given!"))
55		} else {
56			Ok(Self { impls })
57		}
58	}
59}
60
61/// Generates the call to the implementation of the requested function.
62/// The generated code includes decoding of the input arguments and encoding of the output.
63fn generate_impl_call(
64	signature: &Signature,
65	runtime: &Type,
66	input: &Ident,
67	impl_trait: &Path,
68	api_version: &ApiVersion,
69) -> Result<TokenStream> {
70	let params =
71		extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
72
73	let c = generate_crate_access();
74	let fn_name = &signature.ident;
75	let fn_name_str = fn_name.to_string();
76	let pnames = params.iter().map(|v| &v.0);
77	let pnames2 = params.iter().map(|v| &v.0);
78	let ptypes = params.iter().map(|v| &v.1);
79	let pborrow = params.iter().map(|v| &v.2);
80
81	let decode_params = if params.is_empty() {
82		quote!(
83			if !#input.is_empty() {
84				panic!(
85					"Bad input data provided to {}: expected no parameters, but input buffer is not empty. Nothing bad happened: someone sent an invalid transaction to the node.",
86					#fn_name_str
87				);
88			}
89		)
90	} else {
91		let let_binding = if params.len() == 1 {
92			quote! {
93				let #( #pnames )* : #( #ptypes )*
94			}
95		} else {
96			quote! {
97				let ( #( #pnames ),* ) : ( #( #ptypes ),* )
98			}
99		};
100
101		quote!(
102			#let_binding =
103				match #c::Decode::decode(
104					&mut #input,
105				) {
106					Ok(res) => res,
107					Err(e) => panic!("Bad input data provided to {}: {}. Nothing bad happened: someone sent an invalid transaction to the node.", #fn_name_str, e),
108				};
109		)
110	};
111
112	let fn_calls = if let Some(feature_gated) = &api_version.feature_gated {
113		let pnames = pnames2;
114		let pnames2 = pnames.clone();
115		let pborrow2 = pborrow.clone();
116
117		let feature_name = &feature_gated.0;
118		let impl_trait_fg = extend_with_api_version(impl_trait.clone(), Some(feature_gated.1));
119		let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
120
121		quote!(
122			#[cfg(feature = #feature_name)]
123			#[allow(deprecated)]
124			let r = <#runtime as #impl_trait_fg>::#fn_name(#( #pborrow #pnames ),*);
125
126			#[cfg(not(feature = #feature_name))]
127			#[allow(deprecated)]
128			let r = <#runtime as #impl_trait>::#fn_name(#( #pborrow2 #pnames2 ),*);
129
130			r
131		)
132	} else {
133		let pnames = pnames2;
134		let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
135
136		quote!(
137			#[allow(deprecated)]
138			<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames ),*)
139		)
140	};
141
142	Ok(quote!(
143		#decode_params
144
145		#fn_calls
146	))
147}
148
149/// Generate all the implementation calls for the given functions.
150fn generate_impl_calls(
151	impls: &[ItemImpl],
152	input: &Ident,
153) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
154	let mut impl_calls = Vec::new();
155
156	for impl_ in impls {
157		let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
158		let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
159		let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
160		let impl_trait_ident = &impl_trait_path
161			.segments
162			.last()
163			.ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
164			.ident;
165
166		for item in &impl_.items {
167			if let ImplItem::Fn(method) = item {
168				let impl_call = generate_impl_call(
169					&method.sig,
170					&impl_.self_ty,
171					input,
172					&impl_trait,
173					&trait_api_ver,
174				)?;
175				let mut attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
176
177				// Add any `#[cfg(feature = X)]` attributes of the method to result
178				attrs.extend(filter_cfg_and_allow_attrs(&method.attrs));
179
180				impl_calls.push((
181					impl_trait_ident.clone(),
182					method.sig.ident.clone(),
183					impl_call,
184					attrs,
185				));
186			}
187		}
188	}
189
190	Ok(impl_calls)
191}
192
193/// Generate the dispatch function that is used in native to call into the runtime.
194fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
195	let data = Ident::new("_sp_api_input_data_", Span::call_site());
196	let c = generate_crate_access();
197	let impl_calls =
198		generate_impl_calls(impls, &data)?
199			.into_iter()
200			.map(|(trait_, fn_name, impl_, attrs)| {
201				let name = prefix_function_with_trait(&trait_, &fn_name);
202				quote!(
203					#( #attrs )*
204					#name => Some(#c::Encode::encode(&{ #impl_ })),
205				)
206			});
207
208	Ok(quote!(
209		#c::std_enabled! {
210			pub fn dispatch(method: &str, mut #data: &[u8]) -> Option<Vec<u8>> {
211				match method {
212					#( #impl_calls )*
213					_ => None,
214				}
215			}
216		}
217	))
218}
219
220/// Generate the interface functions that are used to call into the runtime in wasm.
221fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
222	let input = Ident::new("input", Span::call_site());
223	let c = generate_crate_access();
224
225	let impl_calls =
226        generate_impl_calls(impls, &input)?
227            .into_iter()
228            .map(|(trait_, fn_name, impl_, attrs)| {
229                let fn_name =
230                    Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
231
232                quote!(
233                    #c::std_disabled! {
234                        #( #attrs )*
235                        #[no_mangle]
236                        #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))]
237                        pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
238                            let mut #input = if input_len == 0 {
239                                &[0u8; 0]
240                            } else {
241                                unsafe {
242                                    ::core::slice::from_raw_parts(input_data, input_len)
243                                }
244                            };
245
246                            #c::init_runtime_logger();
247
248                            let output = (move || { #impl_ })();
249                            #c::to_substrate_wasm_fn_return_value(&output)
250                        }
251                    }
252                )
253            });
254
255	Ok(quote!( #( #impl_calls )* ))
256}
257
258fn generate_runtime_api_base_structures() -> Result<TokenStream> {
259	let crate_ = generate_crate_access();
260
261	Ok(quote!(
262		pub struct RuntimeApi {}
263		#crate_::std_enabled! {
264			/// Implements all runtime apis for the client side.
265			pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
266				call: &'static C,
267				transaction_depth: std::cell::RefCell<u16>,
268				changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor<Block>>>,
269				recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
270				call_context: #crate_::CallContext,
271				extensions: std::cell::RefCell<#crate_::Extensions>,
272				extensions_generated_for: std::cell::RefCell<std::option::Option<Block::Hash>>,
273			}
274
275			#[automatically_derived]
276			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
277				RuntimeApiImpl<Block, C>
278			{
279				fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
280					&self,
281					call: F,
282				) -> R where Self: Sized {
283					self.start_transaction();
284
285					*std::cell::RefCell::borrow_mut(&self.transaction_depth) += 1;
286					let res = call(self);
287					std::cell::RefCell::borrow_mut(&self.transaction_depth)
288						.checked_sub(1)
289						.expect("Transactions are opened and closed together; qed");
290
291					self.commit_or_rollback_transaction(
292						std::matches!(res, #crate_::TransactionOutcome::Commit(_))
293					);
294
295					res.into_inner()
296				}
297
298				fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
299					&self,
300					at: <Block as #crate_::BlockT>::Hash,
301				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
302					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
303					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
304				}
305
306				fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
307					&self,
308					at: <Block as #crate_::BlockT>::Hash,
309					pred: P,
310				) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
311					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
312					.map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))
313				}
314
315				fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
316					&self,
317					at: <Block as #crate_::BlockT>::Hash,
318				) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
319					#crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
320					.map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID))
321				}
322
323				fn record_proof(&mut self) {
324					self.recorder = std::option::Option::Some(std::default::Default::default());
325				}
326
327				fn record_proof_with_recorder(&mut self, recorder: #crate_::ProofRecorder<Block>) {
328					self.recorder = std::option::Option::Some(recorder);
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<u32>) -> 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_and_allow_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_and_allow_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_and_allow_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/// replaces `Self` with explicit `ItemImpl.self_ty`.
791struct ReplaceSelfImpl {
792	self_ty: Box<Type>,
793}
794
795impl ReplaceSelfImpl {
796	/// Replace `Self` with `ItemImpl.self_ty`
797	fn replace(&mut self, trait_: &mut ItemImpl) {
798		visit_mut::visit_item_impl_mut(self, trait_)
799	}
800}
801
802impl VisitMut for ReplaceSelfImpl {
803	fn visit_type_mut(&mut self, ty: &mut syn::Type) {
804		match ty {
805			Type::Path(p) if p.path.is_ident("Self") => {
806				*ty = *self.self_ty.clone();
807			},
808			ty => syn::visit_mut::visit_type_mut(self, ty),
809		}
810	}
811}
812
813/// Rename `Self` to `ItemImpl.self_ty` in all items.
814fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) {
815	impls.iter_mut().for_each(|i| {
816		let mut checker = ReplaceSelfImpl { self_ty: i.self_ty.clone() };
817		checker.replace(i);
818	});
819}
820
821/// The implementation of the `impl_runtime_apis!` macro.
822pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
823	// Parse all impl blocks
824	let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls);
825
826	impl_runtime_apis_impl_inner(&mut api_impls)
827		.unwrap_or_else(|e| e.to_compile_error())
828		.into()
829}
830
831fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result<TokenStream> {
832	rename_self_in_trait_impls(api_impls);
833
834	let dispatch_impl = generate_dispatch_function(api_impls)?;
835	let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
836	let base_runtime_api = generate_runtime_api_base_structures()?;
837	let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
838	let wasm_interface = generate_wasm_interface(api_impls)?;
839	let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
840
841	let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
842
843	let impl_ = quote!(
844		#base_runtime_api
845
846		#api_impls_for_runtime
847
848		#api_impls_for_runtime_api
849
850		#runtime_api_versions
851
852		#runtime_metadata
853
854		pub mod api {
855			use super::*;
856
857			#dispatch_impl
858
859			#wasm_interface
860		}
861	);
862
863	let impl_ = expander::Expander::new("impl_runtime_apis")
864		.dry(std::env::var("EXPAND_MACROS").is_err())
865		.verbose(true)
866		.write_to_out_dir(impl_)
867		.expect("Does not fail because of IO in OUT_DIR; qed");
868
869	Ok(impl_)
870}
871
872// Filters all attributes except the cfg and allow ones.
873fn filter_cfg_and_allow_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
874	attrs
875		.iter()
876		.filter(|a| a.path().is_ident("cfg") || a.path().is_ident("allow"))
877		.cloned()
878		.collect()
879}
880
881#[cfg(test)]
882mod tests {
883	use super::*;
884
885	#[test]
886	fn filter_non_cfg_attributes() {
887		let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
888		let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
889		let allow: Attribute = parse_quote!(#[allow(non_camel_case_types)]);
890
891		let attrs = vec![
892			cfg_std.clone(),
893			parse_quote!(#[derive(Debug)]),
894			parse_quote!(#[test]),
895			cfg_benchmarks.clone(),
896			parse_quote!(#[allow(non_camel_case_types)]),
897		];
898
899		let filtered = filter_cfg_and_allow_attrs(&attrs);
900		assert_eq!(filtered.len(), 3);
901		assert_eq!(cfg_std, filtered[0]);
902		assert_eq!(cfg_benchmarks, filtered[1]);
903		assert_eq!(allow, filtered[2]);
904	}
905
906	#[test]
907	fn impl_trait_rename_self_param() {
908		let code = quote::quote! {
909			impl client::Core<Block> for Runtime {
910				fn initialize_block(header: &HeaderFor<Self>) -> Output<Self> {
911					let _: HeaderFor<Self> = header.clone();
912					example_fn::<Self>(header)
913				}
914			}
915		};
916		let expected = quote::quote! {
917			impl client::Core<Block> for Runtime {
918				fn initialize_block(header: &HeaderFor<Runtime>) -> Output<Runtime> {
919					let _: HeaderFor<Runtime> = header.clone();
920					example_fn::<Runtime>(header)
921				}
922			}
923		};
924
925		// Parse the items
926		let RuntimeApiImpls { impls: mut api_impls } =
927			syn::parse2::<RuntimeApiImpls>(code).unwrap();
928
929		// Run the renamer which is being run first in the `impl_runtime_apis!` macro.
930		rename_self_in_trait_impls(&mut api_impls);
931		let result: TokenStream = quote::quote! {  #(#api_impls)* };
932
933		assert_eq!(result.to_string(), expected.to_string());
934	}
935}