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}