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 proof_recorder(&self) -> std::option::Option<#crate_::ProofRecorder<Block>> {
328					std::clone::Clone::clone(&self.recorder)
329				}
330
331				fn extract_proof(
332					&mut self,
333				) -> std::option::Option<#crate_::StorageProof> {
334					let recorder = std::option::Option::take(&mut self.recorder);
335					std::option::Option::map(recorder, |recorder| {
336						#crate_::ProofRecorder::<Block>::drain_storage_proof(recorder)
337					})
338				}
339
340				fn into_storage_changes<B: #crate_::StateBackend<#crate_::HashingFor<Block>>>(
341					&self,
342					backend: &B,
343					parent_hash: Block::Hash,
344				) -> ::core::result::Result<
345					#crate_::StorageChanges<Block>,
346				String
347					> where Self: Sized {
348						let state_version = #crate_::CallApiAt::<Block>::runtime_version_at(self.call, std::clone::Clone::clone(&parent_hash))
349							.map(|v| #crate_::RuntimeVersion::state_version(&v))
350							.map_err(|e| format!("Failed to get state version: {}", e))?;
351
352						#crate_::OverlayedChanges::drain_storage_changes(
353							&mut std::cell::RefCell::borrow_mut(&self.changes),
354							backend,
355							state_version,
356						)
357					}
358
359				fn set_call_context(&mut self, call_context: #crate_::CallContext) {
360					self.call_context = call_context;
361				}
362
363				fn register_extension<E: #crate_::Extension>(&mut self, extension: E) {
364					std::cell::RefCell::borrow_mut(&self.extensions).register(extension);
365				}
366			}
367
368			#[automatically_derived]
369			impl<Block: #crate_::BlockT, C> #crate_::ConstructRuntimeApi<Block, C>
370				for RuntimeApi
371			where
372				C: #crate_::CallApiAt<Block> + 'static,
373			{
374				type RuntimeApi = RuntimeApiImpl<Block, C>;
375
376				fn construct_runtime_api<'a>(
377					call: &'a C,
378				) -> #crate_::ApiRef<'a, Self::RuntimeApi> {
379					RuntimeApiImpl {
380						call: unsafe { std::mem::transmute(call) },
381						transaction_depth: 0.into(),
382						changes: std::default::Default::default(),
383						recorder: std::default::Default::default(),
384						call_context: #crate_::CallContext::Offchain,
385						extensions: std::default::Default::default(),
386						extensions_generated_for: std::default::Default::default(),
387					}.into()
388				}
389			}
390
391			#[automatically_derived]
392			impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> RuntimeApiImpl<Block, C> {
393				fn commit_or_rollback_transaction(&self, commit: bool) {
394					let proof = "\
395                    We only close a transaction when we opened one ourself.
396                    Other parts of the runtime that make use of transactions (state-machine)
397                    also balance their transactions. The runtime cannot close client initiated
398                    transactions; qed";
399
400					let res = if commit {
401						let res = if let Some(recorder) = &self.recorder {
402							#crate_::ProofRecorder::<Block>::commit_transaction(&recorder)
403						} else {
404							Ok(())
405						};
406
407						let res2 = #crate_::OverlayedChanges::commit_transaction(
408							&mut std::cell::RefCell::borrow_mut(&self.changes)
409						);
410
411						// Will panic on an `Err` below, however we should call commit
412						// on the recorder and the changes together.
413						std::result::Result::and(res, std::result::Result::map_err(res2, drop))
414					} else {
415						let res = if let Some(recorder) = &self.recorder {
416							#crate_::ProofRecorder::<Block>::rollback_transaction(&recorder)
417						} else {
418							Ok(())
419						};
420
421						let res2 = #crate_::OverlayedChanges::rollback_transaction(
422							&mut std::cell::RefCell::borrow_mut(&self.changes)
423						);
424
425						// Will panic on an `Err` below, however we should call commit
426						// on the recorder and the changes together.
427						std::result::Result::and(res, std::result::Result::map_err(res2, drop))
428					};
429
430					std::result::Result::expect(res, proof);
431				}
432
433				fn start_transaction(&self) {
434					#crate_::OverlayedChanges::start_transaction(
435						&mut std::cell::RefCell::borrow_mut(&self.changes)
436					);
437					if let Some(recorder) = &self.recorder {
438						#crate_::ProofRecorder::<Block>::start_transaction(&recorder);
439					}
440				}
441			}
442		}
443	))
444}
445
446/// Extend the given trait path with module that contains the declaration of the trait for the
447/// runtime.
448fn extend_with_runtime_decl_path(mut trait_: Path) -> Path {
449	let runtime = {
450		let trait_name = &trait_
451			.segments
452			.last()
453			.as_ref()
454			.expect("Trait path should always contain at least one item; qed")
455			.ident;
456
457		generate_runtime_mod_name_for_trait(trait_name)
458	};
459
460	let pos = trait_.segments.len() - 1;
461	trait_.segments.insert(pos, runtime.into());
462	trait_
463}
464
465fn extend_with_api_version(mut trait_: Path, version: Option<u32>) -> Path {
466	let version = if let Some(v) = version {
467		v
468	} else {
469		// nothing to do
470		return trait_;
471	};
472
473	let trait_name = &mut trait_
474		.segments
475		.last_mut()
476		.expect("Trait path should always contain at least one item; qed")
477		.ident;
478	*trait_name = versioned_trait_name(trait_name, version);
479
480	trait_
481}
482
483/// Adds a feature guard to `attributes`.
484///
485/// Depending on `enable`, the feature guard either enables ('feature = "something"`) or disables
486/// (`not(feature = "something")`).
487fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
488	let attr = match enable {
489		true => parse_quote!(#[cfg(feature = #feature_name)]),
490		false => parse_quote!(#[cfg(not(feature = #feature_name))]),
491	};
492	attrs.push(attr);
493}
494
495/// Generates the implementations of the apis for the runtime.
496fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
497	let mut impls_prepared = Vec::new();
498
499	// We put `runtime` before each trait to get the trait that is intended for the runtime and
500	// we put the `RuntimeBlock` as first argument for the trait generics.
501	for impl_ in impls.iter() {
502		let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
503
504		let mut impl_ = impl_.clone();
505		impl_.attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
506
507		let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone();
508		let trait_ = extend_with_runtime_decl_path(trait_);
509		// If the trait api contains feature gated version - there are staging methods in it. Handle
510		// them explicitly here by adding staging implementation with `#cfg(feature = ...)` and
511		// stable implementation with `#[cfg(not(feature = ...))]`.
512		if let Some(feature_gated) = trait_api_ver.feature_gated {
513			let mut feature_gated_impl = impl_.clone();
514			add_feature_guard(&mut feature_gated_impl.attrs, &feature_gated.0, true);
515			feature_gated_impl.trait_.as_mut().unwrap().1 =
516				extend_with_api_version(trait_.clone(), Some(feature_gated.1));
517
518			impls_prepared.push(feature_gated_impl);
519
520			// Finally add `#[cfg(not(feature = ...))]` for the stable implementation (which is
521			// generated outside this if).
522			add_feature_guard(&mut impl_.attrs, &feature_gated.0, false);
523		}
524
525		// Generate stable trait implementation.
526		let trait_ = extend_with_api_version(trait_, trait_api_ver.custom);
527		impl_.trait_.as_mut().unwrap().1 = trait_;
528		impls_prepared.push(impl_);
529	}
530
531	Ok(quote!( #( #impls_prepared )* ))
532}
533
534/// Auxiliary data structure that is used to convert `impl Api for Runtime` to
535/// `impl Api for RuntimeApi`.
536/// This requires us to replace the runtime `Block` with the node `Block`,
537/// `impl Api for Runtime` with `impl Api for RuntimeApi` and replace the method implementations
538/// with code that calls into the runtime.
539struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
540	runtime_block: &'a TypePath,
541}
542
543impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
544	/// Process the given item implementation.
545	fn process(mut self, input: ItemImpl) -> ItemImpl {
546		let mut input = self.fold_item_impl(input);
547
548		let crate_ = generate_crate_access();
549
550		// Delete all functions, because all of them are default implemented by
551		// `decl_runtime_apis!`. We only need to implement the `__runtime_api_internal_call_api_at`
552		// function.
553		input.items.clear();
554		input.items.push(parse_quote! {
555			fn __runtime_api_internal_call_api_at(
556				&self,
557				at: <__SrApiBlock__ as #crate_::BlockT>::Hash,
558				params: std::vec::Vec<u8>,
559				fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
560			) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
561				// If we are not already in a transaction, we should create a new transaction
562				// and then commit/roll it back at the end!
563				let transaction_depth = *std::cell::RefCell::borrow(&self.transaction_depth);
564
565				if transaction_depth == 0 {
566					self.start_transaction();
567				}
568
569				let res = (|| {
570					let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at(
571						self.call,
572						at,
573					)?;
574
575					match &mut *std::cell::RefCell::borrow_mut(&self.extensions_generated_for) {
576						Some(generated_for) => {
577							if *generated_for != at {
578								return std::result::Result::Err(
579									#crate_::ApiError::UsingSameInstanceForDifferentBlocks
580								)
581							}
582						},
583						generated_for @ None => {
584							#crate_::CallApiAt::<__SrApiBlock__>::initialize_extensions(
585								self.call,
586								at,
587								&mut std::cell::RefCell::borrow_mut(&self.extensions),
588							)?;
589
590							*generated_for = Some(at);
591						}
592					}
593
594					let params = #crate_::CallApiAtParams {
595						at,
596						function: (*fn_name)(version),
597						arguments: params,
598						overlayed_changes: &self.changes,
599						call_context: self.call_context,
600						recorder: &self.recorder,
601						extensions: &self.extensions,
602					};
603
604					#crate_::CallApiAt::<__SrApiBlock__>::call_api_at(
605						self.call,
606						params,
607					)
608				})();
609
610				if transaction_depth == 0 {
611					self.commit_or_rollback_transaction(std::result::Result::is_ok(&res));
612				}
613
614				res
615			}
616		});
617
618		input
619	}
620}
621
622impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
623	fn fold_type_path(&mut self, input: TypePath) -> TypePath {
624		let new_ty_path =
625			if input == *self.runtime_block { parse_quote!(__SrApiBlock__) } else { input };
626
627		fold::fold_type_path(self, new_ty_path)
628	}
629
630	fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl {
631		let crate_ = generate_crate_access();
632
633		// Implement the trait for the `RuntimeApiImpl`
634		input.self_ty =
635			Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> ));
636
637		input.generics.params.push(parse_quote!(
638			__SrApiBlock__: #crate_::BlockT
639		));
640
641		input
642			.generics
643			.params
644			.push(parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SrApiBlock__> + 'static ));
645
646		let where_clause = input.generics.make_where_clause();
647
648		where_clause.predicates.push(parse_quote! {
649			RuntimeApiImplCall::StateBackend:
650				#crate_::StateBackend<#crate_::HashingFor<__SrApiBlock__>>
651		});
652
653		where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send });
654
655		input.attrs = filter_cfg_and_allow_attrs(&input.attrs);
656
657		fold::fold_item_impl(self, input)
658	}
659}
660
661/// Generate the implementations of the runtime apis for the `RuntimeApi` type.
662fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream> {
663	let mut result = Vec::with_capacity(impls.len());
664
665	for impl_ in impls {
666		let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
667		let runtime_block = extract_block_type_from_trait_path(impl_trait_path)?;
668		let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone());
669		// remove the trait to get just the module path
670		runtime_mod_path.segments.pop();
671
672		let mut processed_impl =
673			ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone());
674
675		processed_impl.attrs.push(parse_quote!(#[automatically_derived]));
676
677		result.push(processed_impl);
678	}
679
680	let crate_ = generate_crate_access();
681
682	Ok(quote!( #crate_::std_enabled! { #( #result )* } ))
683}
684
685fn populate_runtime_api_versions(
686	result: &mut Vec<TokenStream>,
687	sections: &mut Vec<TokenStream>,
688	attrs: Vec<Attribute>,
689	id: Path,
690	version: TokenStream,
691	crate_access: &TokenStream,
692) {
693	result.push(quote!(
694			#( #attrs )*
695			(#id, #version)
696	));
697
698	sections.push(quote!(
699		#crate_access::std_disabled! {
700			#( #attrs )*
701			const _: () = {
702				// All sections with the same name are going to be merged by concatenation.
703				#[link_section = "runtime_apis"]
704				static SECTION_CONTENTS: [u8; 12] = #crate_access::serialize_runtime_api_info(#id, #version);
705			};
706		}
707	));
708}
709
710/// Generates `RUNTIME_API_VERSIONS` that holds all version information about the implemented
711/// runtime apis.
712fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
713	let mut result = Vec::<TokenStream>::with_capacity(impls.len());
714	let mut sections = Vec::<TokenStream>::with_capacity(impls.len());
715	let mut processed_traits = HashMap::new();
716
717	let c = generate_crate_access();
718
719	for impl_ in impls {
720		let versions = extract_api_version(&impl_.attrs, impl_.span())?;
721		let api_ver = versions.custom.map(|a| a as u32);
722
723		let mut path = extend_with_runtime_decl_path(
724			extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(),
725		);
726		// Remove the trait
727		let trait_ = path
728			.segments
729			.pop()
730			.expect("extract_impl_trait already checks that this is valid; qed")
731			.into_value()
732			.ident;
733
734		let span = trait_.span();
735		if let Some(other_span) = processed_traits.insert(trait_, span) {
736			let mut error = Error::new(
737				span,
738				"Two traits with the same name detected! \
739                    The trait name is used to generate its ID. \
740                    Please rename one trait at the declaration!",
741			);
742
743			error.combine(Error::new(other_span, "First trait implementation."));
744
745			return Err(error);
746		}
747
748		let id: Path = parse_quote!( #path ID );
749		let mut attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
750
751		// Handle API versioning
752		// If feature gated version is set - handle it first
753		if let Some(feature_gated) = versions.feature_gated {
754			let feature_gated_version = feature_gated.1 as u32;
755			// the attributes for the feature gated staging api
756			let mut feature_gated_attrs = attrs.clone();
757			add_feature_guard(&mut feature_gated_attrs, &feature_gated.0, true);
758			populate_runtime_api_versions(
759				&mut result,
760				&mut sections,
761				feature_gated_attrs,
762				id.clone(),
763				quote!( #feature_gated_version ),
764				&c,
765			);
766
767			// Add `#[cfg(not(feature ...))]` to the initial attributes. If the staging feature flag
768			// is not set we want to set the stable api version
769			add_feature_guard(&mut attrs, &feature_gated.0, false);
770		}
771
772		// Now add the stable api version to the versions list. If the api has got staging functions
773		// there might be a `#[cfg(not(feature ...))]` attribute attached to the stable version.
774		let base_api_version = quote!( #path VERSION );
775		let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version);
776		populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c);
777	}
778
779	Ok(quote!(
780		pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
781
782		#( #sections )*
783	))
784}
785
786/// replaces `Self` with explicit `ItemImpl.self_ty`.
787struct ReplaceSelfImpl {
788	self_ty: Box<Type>,
789}
790
791impl ReplaceSelfImpl {
792	/// Replace `Self` with `ItemImpl.self_ty`
793	fn replace(&mut self, trait_: &mut ItemImpl) {
794		visit_mut::visit_item_impl_mut(self, trait_)
795	}
796}
797
798impl VisitMut for ReplaceSelfImpl {
799	fn visit_type_mut(&mut self, ty: &mut syn::Type) {
800		match ty {
801			Type::Path(p) if p.path.is_ident("Self") => {
802				*ty = *self.self_ty.clone();
803			},
804			ty => syn::visit_mut::visit_type_mut(self, ty),
805		}
806	}
807}
808
809/// Rename `Self` to `ItemImpl.self_ty` in all items.
810fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) {
811	impls.iter_mut().for_each(|i| {
812		let mut checker = ReplaceSelfImpl { self_ty: i.self_ty.clone() };
813		checker.replace(i);
814	});
815}
816
817/// The implementation of the `impl_runtime_apis!` macro.
818pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
819	// Parse all impl blocks
820	let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls);
821
822	impl_runtime_apis_impl_inner(&mut api_impls)
823		.unwrap_or_else(|e| e.to_compile_error())
824		.into()
825}
826
827fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result<TokenStream> {
828	rename_self_in_trait_impls(api_impls);
829
830	let dispatch_impl = generate_dispatch_function(api_impls)?;
831	let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
832	let base_runtime_api = generate_runtime_api_base_structures()?;
833	let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
834	let wasm_interface = generate_wasm_interface(api_impls)?;
835	let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
836
837	let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
838
839	let impl_ = quote!(
840		#base_runtime_api
841
842		#api_impls_for_runtime
843
844		#api_impls_for_runtime_api
845
846		#runtime_api_versions
847
848		#runtime_metadata
849
850		pub mod api {
851			use super::*;
852
853			#dispatch_impl
854
855			#wasm_interface
856		}
857	);
858
859	let impl_ = expander::Expander::new("impl_runtime_apis")
860		.dry(std::env::var("EXPAND_MACROS").is_err())
861		.verbose(true)
862		.write_to_out_dir(impl_)
863		.expect("Does not fail because of IO in OUT_DIR; qed");
864
865	Ok(impl_)
866}
867
868// Filters all attributes except the cfg and allow ones.
869fn filter_cfg_and_allow_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
870	attrs
871		.iter()
872		.filter(|a| a.path().is_ident("cfg") || a.path().is_ident("allow"))
873		.cloned()
874		.collect()
875}
876
877#[cfg(test)]
878mod tests {
879	use super::*;
880
881	#[test]
882	fn filter_non_cfg_attributes() {
883		let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
884		let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
885		let allow: Attribute = parse_quote!(#[allow(non_camel_case_types)]);
886
887		let attrs = vec![
888			cfg_std.clone(),
889			parse_quote!(#[derive(Debug)]),
890			parse_quote!(#[test]),
891			cfg_benchmarks.clone(),
892			parse_quote!(#[allow(non_camel_case_types)]),
893		];
894
895		let filtered = filter_cfg_and_allow_attrs(&attrs);
896		assert_eq!(filtered.len(), 3);
897		assert_eq!(cfg_std, filtered[0]);
898		assert_eq!(cfg_benchmarks, filtered[1]);
899		assert_eq!(allow, filtered[2]);
900	}
901
902	#[test]
903	fn impl_trait_rename_self_param() {
904		let code = quote::quote! {
905			impl client::Core<Block> for Runtime {
906				fn initialize_block(header: &HeaderFor<Self>) -> Output<Self> {
907					let _: HeaderFor<Self> = header.clone();
908					example_fn::<Self>(header)
909				}
910			}
911		};
912		let expected = quote::quote! {
913			impl client::Core<Block> for Runtime {
914				fn initialize_block(header: &HeaderFor<Runtime>) -> Output<Runtime> {
915					let _: HeaderFor<Runtime> = header.clone();
916					example_fn::<Runtime>(header)
917				}
918			}
919		};
920
921		// Parse the items
922		let RuntimeApiImpls { impls: mut api_impls } =
923			syn::parse2::<RuntimeApiImpls>(code).unwrap();
924
925		// Run the renamer which is being run first in the `impl_runtime_apis!` macro.
926		rename_self_in_trait_impls(&mut api_impls);
927		let result: TokenStream = quote::quote! {  #(#api_impls)* };
928
929		assert_eq!(result.to_string(), expected.to_string());
930	}
931}