precompile_utils_macro/precompile/
mod.rs

1// This file is part of Frontier.
2
3// Copyright (c) Moonsong Labs.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0
6
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// 	http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18
19#![doc = include_str!("../../docs/precompile_macro.md")]
20
21use proc_macro::TokenStream;
22use proc_macro2::Span;
23use quote::{format_ident, quote, quote_spanned, ToTokens};
24use sp_crypto_hashing::keccak_256;
25use std::collections::BTreeMap;
26use syn::{parse_macro_input, spanned::Spanned};
27
28pub mod attr;
29pub mod expand;
30pub mod parse;
31
32pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
33	// Macro must be used on `impl` block.
34	let mut impl_item = parse_macro_input!(item as syn::ItemImpl);
35
36	// We inspect the block to collect all the data we need for the
37	// expansion, and make various checks.
38	let precompile = match Precompile::try_from(&mut impl_item) {
39		Ok(p) => p,
40		Err(e) => return e.into_compile_error().into(),
41	};
42
43	// We generate additional code based on the collected data.
44	let new_items = precompile.expand();
45	let output = quote!(
46		#impl_item
47		#new_items
48	);
49
50	output.into()
51}
52
53struct Precompile {
54	/// Impl struct type.
55	impl_type: syn::Type,
56
57	/// Impl struct ident.
58	impl_ident: syn::Ident,
59
60	/// New parsing enum ident.
61	enum_ident: syn::Ident,
62
63	/// Generic part that needs to also be used by the input enum.
64	generics: syn::Generics,
65
66	/// Which selector corresponds to which variant of the input enum.
67	selector_to_variant: BTreeMap<u32, syn::Ident>,
68
69	/// Optional fallback function if no selector matches.
70	fallback_to_variant: Option<syn::Ident>,
71
72	/// Describes the content of each variant based on the precompile methods.
73	variants_content: BTreeMap<syn::Ident, Variant>,
74
75	/// Since being a precompile set implies lots of changes, we must know it early
76	/// in the form of an attribute on the impl block itself.
77	tagged_as_precompile_set: bool,
78
79	/// Ident of the function returning the PrecompileSet discriminant.
80	precompile_set_discriminant_fn: Option<syn::Ident>,
81
82	/// Type of the PrecompileSet discriminant.
83	precompile_set_discriminant_type: Option<syn::Type>,
84
85	/// When generating the selector test the data types might depend on type parameters.
86	/// The test thus need to be written using concrete types.
87	test_concrete_types: Option<Vec<syn::Type>>,
88
89	/// Ident of a function that performs a check before the call is dispatched to the proper
90	/// function.
91	pre_check: Option<syn::Ident>,
92}
93
94#[derive(Debug, PartialEq, Eq)]
95enum Modifier {
96	NonPayable,
97	Payable,
98	View,
99}
100
101#[derive(Debug)]
102struct Variant {
103	/// Description of the arguments of this method, which will also
104	/// be members of a struct variant.
105	arguments: Vec<Argument>,
106
107	/// String extracted from the selector attribute.
108	/// A unit test will be generated to check that this selector matches
109	/// the Rust arguments.
110	///
111	/// > solidity::Codec trait allows to generate this string at runtime only. Thus
112	/// > it is required to write it manually in the selector attribute, and
113	/// > a unit test is generated to check it matches.
114	solidity_arguments_type: String,
115
116	/// Modifier of the function. They are all exclusive and defaults to
117	/// `NonPayable`.
118	modifier: Modifier,
119
120	/// Selectors of this function to be able to encode back the data.
121	/// Empty if it only the fallback function.
122	selectors: Vec<u32>,
123
124	/// Output of the variant fn (for better error messages).
125	fn_output: syn::Type,
126}
127
128#[derive(Debug)]
129struct Argument {
130	/// Identifier of the argument, which will be used in the struct variant.
131	ident: syn::Ident,
132
133	/// Type of the argument, which will be used in the struct variant and
134	/// to parse the input.
135	ty: syn::Type,
136}