diff --git a/Cargo.lock b/Cargo.lock index 7bb30965c3..92db87c8fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1205,15 +1205,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "basic-toml" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" -dependencies = [ - "serde", -] - [[package]] name = "bech32" version = "0.9.1" @@ -3104,12 +3095,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "difflib" version = "0.4.0" @@ -6786,22 +6771,6 @@ dependencies = [ "syn 2.0.66", ] -[[package]] -name = "macrotest" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c373046e96714b07b66d572e8b43e48d67cad110fd3f5bf2e000e58751864d2d" -dependencies = [ - "basic-toml", - "diff", - "glob", - "prettyplease 0.2.20", - "serde", - "serde_derive", - "serde_json", - "syn 2.0.66", -] - [[package]] name = "match_cfg" version = "0.1.0" @@ -11457,6 +11426,7 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "precompile-utils" version = "0.1.0" +source = "git+https://github.com/AstarNetwork/frontier?branch=polkadot-v1.11.0#1daafa80fc18800e56a0ac60f02a60353240235c" dependencies = [ "derive_more", "environmental", @@ -11468,36 +11438,32 @@ dependencies = [ "hex-literal", "impl-trait-for-tuples", "log", - "num_enum 0.5.11", + "num_enum 0.7.2", "pallet-evm", "parity-scale-codec", - "precompile-utils-macro-v2", + "precompile-utils-macro", "scale-info", "serde", "similar-asserts", "sp-core", "sp-io", "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "sp-weights", "staging-xcm", ] [[package]] -name = "precompile-utils-macro-v2" +name = "precompile-utils-macro" version = "0.1.0" +source = "git+https://github.com/AstarNetwork/frontier?branch=polkadot-v1.11.0#1daafa80fc18800e56a0ac60f02a60353240235c" dependencies = [ "case", - "fp-evm", - "frame-support", - "macrotest", - "num_enum 0.5.11", + "num_enum 0.7.2", "prettyplease 0.2.20", "proc-macro2", "quote", - "sp-core-hashing", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0)", + "sp-crypto-hashing", "syn 1.0.109", - "trybuild", ] [[package]] @@ -15236,14 +15202,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "sp-core-hashing" -version = "15.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.11.0#8c8edacf8942298c3807a2e192860da9e7e4996a" -dependencies = [ - "sp-crypto-hashing", -] - [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" @@ -16892,20 +16850,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "trybuild" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3" -dependencies = [ - "glob", - "serde", - "serde_derive", - "serde_json", - "termcolor", - "toml 0.8.14", -] - [[package]] name = "tt-call" version = "1.0.9" diff --git a/Cargo.toml b/Cargo.toml index ff5958fb28..11603e94cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -208,6 +208,7 @@ pallet-base-fee = { git = "https://github.com/AstarNetwork/frontier", branch = " pallet-evm-chain-id = { git = "https://github.com/AstarNetwork/frontier", branch = "polkadot-v1.11.0", default-features = false } fp-evm = { git = "https://github.com/AstarNetwork/frontier", branch = "polkadot-v1.11.0", default-features = false } fp-ethereum = { git = "https://github.com/AstarNetwork/frontier", branch = "polkadot-v1.11.0", default-features = false } +precompile-utils = { git = "https://github.com/AstarNetwork/frontier", branch = "polkadot-v1.11.0", default-features = false } # (native) fc-consensus = { git = "https://github.com/AstarNetwork/frontier", branch = "polkadot-v1.11.0" } @@ -313,8 +314,6 @@ pallet-chain-extension-unified-accounts = { path = "./chain-extensions/unified-a assets-chain-extension-types = { path = "./chain-extensions/types/assets", default-features = false } unified-accounts-chain-extension-types = { path = "./chain-extensions/types/unified-accounts", default-features = false } -precompile-utils = { path = "./precompiles/utils", default-features = false } - local-runtime = { path = "./runtime/local", default-features = false } shibuya-runtime = { path = "./runtime/shibuya", default-features = false } shiden-runtime = { path = "./runtime/shiden", default-features = false } diff --git a/bin/collator/src/local/chain_spec.rs b/bin/collator/src/local/chain_spec.rs index 21bfd479b6..e545408bc8 100644 --- a/bin/collator/src/local/chain_spec.rs +++ b/bin/collator/src/local/chain_spec.rs @@ -128,7 +128,7 @@ fn testnet_genesis( evm: EVMConfig { // We need _some_ code inserted at the precompile address so that // the evm will actually call the address. - accounts: Precompiles::used_addresses() + accounts: Precompiles::used_addresses_h160() .map(|addr| { ( addr, diff --git a/bin/collator/src/parachain/chain_spec/astar.rs b/bin/collator/src/parachain/chain_spec/astar.rs index bd27660599..f5e0ec3491 100644 --- a/bin/collator/src/parachain/chain_spec/astar.rs +++ b/bin/collator/src/parachain/chain_spec/astar.rs @@ -134,7 +134,7 @@ fn make_genesis( evm: EVMConfig { // We need _some_ code inserted at the precompile address so that // the evm will actually call the address. - accounts: Precompiles::used_addresses() + accounts: Precompiles::used_addresses_h160() .map(|addr| { ( addr, diff --git a/bin/collator/src/parachain/chain_spec/shibuya.rs b/bin/collator/src/parachain/chain_spec/shibuya.rs index 0a2d52d4f7..cab9754a5c 100644 --- a/bin/collator/src/parachain/chain_spec/shibuya.rs +++ b/bin/collator/src/parachain/chain_spec/shibuya.rs @@ -142,7 +142,7 @@ fn make_genesis( evm: EVMConfig { // We need _some_ code inserted at the precompile address so that // the evm will actually call the address. - accounts: Precompiles::used_addresses() + accounts: Precompiles::used_addresses_h160() .map(|addr| { ( addr, diff --git a/bin/collator/src/parachain/chain_spec/shiden.rs b/bin/collator/src/parachain/chain_spec/shiden.rs index 17fe56e8bf..a0d77b4456 100644 --- a/bin/collator/src/parachain/chain_spec/shiden.rs +++ b/bin/collator/src/parachain/chain_spec/shiden.rs @@ -136,7 +136,7 @@ fn make_genesis( evm: EVMConfig { // We need _some_ code inserted at the precompile address so that // the evm will actually call the address. - accounts: Precompiles::used_addresses() + accounts: Precompiles::used_addresses_h160() .map(|addr| { ( addr, diff --git a/precompiles/utils/Cargo.toml b/precompiles/utils/Cargo.toml deleted file mode 100644 index 0255e214b7..0000000000 --- a/precompiles/utils/Cargo.toml +++ /dev/null @@ -1,66 +0,0 @@ -[package] -name = "precompile-utils" -authors = { workspace = true } -description = "Utils to write EVM precompiles." -edition = "2021" -version = "0.1.0" - -[dependencies] -derive_more = { workspace = true, optional = true } -environmental = { workspace = true } -hex = { workspace = true } -hex-literal = { workspace = true, optional = true } -impl-trait-for-tuples = { workspace = true } -log = { workspace = true } -num_enum = { workspace = true } -scale-info = { workspace = true, optional = true, features = ["derive"] } -serde = { workspace = true, optional = true } -similar-asserts = { workspace = true, optional = true } - -# Frontier -precompile-utils-macro-v2 = { path = "macro" } - -# Substrate -frame-support = { workspace = true } -frame-system = { workspace = true } -parity-scale-codec = { workspace = true } -sp-core = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -# Frontier -evm = { workspace = true, features = ["with-codec"] } -fp-evm = { workspace = true } -pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } - -# Polkadot / XCM -xcm = { workspace = true, optional = true } - -[dev-dependencies] -hex-literal = { workspace = true } -xcm = { workspace = true } - -[features] -default = ["std"] -std = [ - "environmental/std", - "fp-evm/std", - "frame-support/std", - "frame-system/std", - "pallet-evm/std", - "parity-scale-codec/std", - "sp-core/std", - "sp-io/std", - "sp-std/std", - "xcm?/std", - "evm/std", - "hex/std", - "log/std", - "num_enum/std", - "scale-info?/std", - "serde?/std", - "sp-runtime/std", -] -codec-xcm = ["xcm"] -testing = ["derive_more", "hex-literal", "scale-info", "serde", "similar-asserts", "std"] diff --git a/precompiles/utils/macro/Cargo.toml b/precompiles/utils/macro/Cargo.toml deleted file mode 100644 index a7365118af..0000000000 --- a/precompiles/utils/macro/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "precompile-utils-macro-v2" -authors = { workspace = true } -description = "" -edition = "2021" -version = "0.1.0" - -[lib] -proc-macro = true - -[[test]] -name = "tests" -path = "tests/tests.rs" - -[dependencies] -case = "1.0" -num_enum = { workspace = true } -prettyplease = "0.2.12" -proc-macro2 = "1.0" -quote = "1.0" -sp-core-hashing = { workspace = true } -syn = { version = "1.0", features = ["extra-traits", "fold", "full", "visit"] } - -[dev-dependencies] -macrotest = "1.0.9" -trybuild = "1.0" - -# precompile-utils = { path = "../", features = ["testing"] } - -fp-evm = { workspace = true } -frame-support = { workspace = true } -sp-core-hashing = { workspace = true } -sp-std = { workspace = true } - -[features] -default = ["std"] -std = [ - "fp-evm/std", - "frame-support/std", - "sp-core-hashing/std", - "sp-std/std", - "num_enum/std", -] diff --git a/precompiles/utils/macro/docs/precompile_macro.md b/precompiles/utils/macro/docs/precompile_macro.md deleted file mode 100644 index e72a4e002a..0000000000 --- a/precompiles/utils/macro/docs/precompile_macro.md +++ /dev/null @@ -1,199 +0,0 @@ -# `#[precompile]` procedural macro. - -This procedural macro allows to simplify the implementation of an EVM precompile or precompile set -using an `impl` block with annotations to automatically generate: - -- the implementation of the trait `Precompile` or `PrecompileSet` (exposed by the `fp_evm` crate) -- parsing of the method parameters from Solidity encoding into Rust type, based on the `solidity::Codec` - trait (exposed by the `precompile-utils` crate) -- a test to ensure the types expressed in the Solidity signature match the Rust types in the - implementation. - -## How to use - -Define your precompile type and write an `impl` block that will contain the precompile methods -implementation. This `impl` block can have type parameters and a `where` clause, which will be -reused to generate the `Precompile`/`PrecompileSet` trait implementation and the enum representing -each public function of precompile with its parsed arguments. - -```rust,ignore -pub struct ExemplePrecompile(PhantomData<(R,I)>); - -#[precomile_utils::precompile] -impl ExemplePrecompile -where - R: pallet_evm::Config -{ - #[precompile::public("example(uint32)")] - fn example(handle: &mut impl PrecompileHandle, arg: u32) -> EvmResult { - Ok(arg * 2) - } -} -``` - -The example code above will automatically generate an enum like - -```rust,ignore -#[allow(non_camel_case_types)] -pub enum ExemplePrecompileCall -where - R: pallet_evm::Config -{ - example { - arg: u32 - }, - // + an non constrible variant with a PhantomData<(R,I)> -} -``` - -This enum have the function `parse_call_data` that can parse the calldata, recognize the Solidity -4-bytes selector and parse the appropriate enum variant. - -It will also generate automatically an implementation of `Precompile`/`PrecompileSet` that calls -this function and the content of the variant to its associated function of the `impl` block. - -## Function attributes - -`#[precompile::public("signature")]` allows to declare a function as a public method of the -precompile with the provided Solidity signature. A function can have multiple `public` attributes to -support renamed functions with backward compatibility, however the arguments must have the same -type. It is not allowed to use the exact same signature multiple times. - -The function must take a `&mut impl PrecompileHandle` as parameter, followed by all the parameters -of the Solidity function in the same order. Those parameters types must implement `solidity::Codec`, and -their name should match the one used in the Solidity interface (.sol) while being in `snake_case`, -which will automatically be converted to `camelCase` in revert messages. The function must return an -`EvmResult`, which is an alias of `Result`. This `T` must implement the -`solidity::Codec` trait and must match the return type in the Solidity interface. The macro will -automatically encode it to Solidity format. - -By default those functions are considered non-payable and non-view (can cause state changes). This -can be changed using either `#[precompile::payable]` or `#[precompile::view]`. Only one can be used. - -It is also possible to declare a fallback function using `#[precompile::fallback]`. This function -will be called if the selector is unknown or if the input is less than 4-bytes long (no selector). -This function cannot have any parameter outside of the `PrecompileHandle`. A function can be both -`public` and `fallback`. - -In case some check must be performed before parsing the input, such as forbidding being called from -some address, a function can be annotated with `#[precompile::pre_check]`: - -```rust,ignore -#[precompile::pre_check] -fn pre_check(handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("Perform your check here") -} -``` - -This function cannot have other attributes. - -## PrecompileSet - -By default the macro considers the `impl` block to represent a precompile and this will implement -the `Precompile` trait. If you want to instead implement a precompile set, you must add the -`#[precompile::precompile_set]` to the `impl` block. - -Then, it is necessary to have a function annotated with the `#[precompile::discriminant]` attribute. -This function is called with the **code address**, the address of the precompile. It must return -`None` if this address is not part of the precompile set, or `Some` if it is. The `Some` variants -contains a value of a type of your choice that represents which member of the set this address -corresponds to. For example for our XC20 precompile sets this function returns the asset id -corresponding to this address if it exists. - -Finally, every other function annotated with a `precompile::_` attribute must now take this -discriminant as first parameter, before the `PrecompileHandle`. - -```rust,ignore -pub struct ExemplePrecompileSet(PhantomData); - -#[precompile_utils::precompile] -#[precompile::precompile_set] -impl ExamplePrecompileSet -where - R: pallet_evm::Config -{ - #[precompile::discriminant] - fn discriminant(address: H160) -> Option { - // Replace with your discriminant logic. - Some(match address { - a if a == H160::from(42) => 1 - a if a == H160::from(43) => 2, - _ => return None, - }) - } - - #[precompile::public("example(uint32)")] - fn example(discriminant: u8, handle: &mut impl PrecompileHandle, arg: u32) -> EvmResult { - // Discriminant can be used here. - Ok(arg * discriminant) - } -} -``` - -## Solidity signatures test - -The macro will automatically generate a unit test to ensure that the types expressed in a `public` -attribute matches the Rust parameters of the function, thanks to the `solidity::Codec` trait having the -`solidity_type() -> String` function. - -If any **parsed** argument (discriminant is not concerned) depends on the type parameters of the -`impl` block, the macro will not be able to produce valid code and output an error like: - -```text -error[E0412]: cannot find type `R` in this scope - --> tests/precompile/compile-fail/test/generic-arg.rs:25:63 - | -23 | impl> Precompile { - | - help: you might be missing a type parameter: `` -24 | #[precompile::public("foo(bytes)")] -25 | fn foo(handle: &mut impl PrecompileHandle, arg: BoundedBytes) -> EvmResult { - | ^ not found in this scope -``` - -In this case you need to annotate the `impl` block with the `#[precompile::test_concrete_types(...)]` -attributes. The `...` should be replaced with concrete types for each type parameter, like a mock -runtime. Those types are only used to generate the test and only one set of types can be used. - -```rust,ignore -pub struct ExamplePrecompile(PhantomData<(R, I)>); - -pub struct GetMaxSize(PhantomData<(R, I)>); - -impl Get for GetMaxSize { - fn get() -> u32 { - >::SomeConstant::get() - } -} - -#[precompile_utils::precompile] -#[precompile::test_concrete_types(mock::Runtime, Instance1)] -impl ExamplePrecompile -where - R: pallet_evm::Config + SomeConfig -{ - #[precompile::public("example(bytes)")] - fn example( - handle: &mut impl PrecompileHandle, - data: BoundedBytes>, - ) -> EvmResult { - todo!("Method implementation") - } -} -``` - -## Enum functions - -The generated enums exposes the following public functions: - -- `parse_call_data`: take a `PrecompileHandle` and tries to parse the call data. Returns an - `EvmResult`. It **DOES NOT** execute the code of the annotated `impl` block. -- `supports_selector`: take a selector as a `u32` is returns if this selector is supported by the - precompile(set) as a `bool`. Note that the presence of a fallback function is not taken into - account. -- `selectors`: returns a static array (`&'static [u32]`) of all the supported selectors. -- For each variant/public function `foo`, there is a function `foo_selectors` which returns a static - array of all the supported selectors **for that function**. That can be used to ensure in tests - that some function have a selector that was computed by hand. -- `encode`: take `self` and encodes it in Solidity format. Additionally, `Vec` implements - `From` which simply call encodes. This is useful to write tests as you can construct the - variant you want and it will be encoded to Solidity format for you. diff --git a/precompiles/utils/macro/src/derive_codec.rs b/precompiles/utils/macro/src/derive_codec.rs deleted file mode 100644 index f1bcdf1f02..0000000000 --- a/precompiles/utils/macro/src/derive_codec.rs +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{quote, quote_spanned}; -use syn::{ - parse_macro_input, punctuated::Punctuated, spanned::Spanned, DeriveInput, Ident, LitStr, Path, - PathSegment, PredicateType, TraitBound, TraitBoundModifier, -}; - -pub fn main(input: TokenStream) -> TokenStream { - let DeriveInput { - ident, - mut generics, - data, - .. - } = parse_macro_input!(input as DeriveInput); - - let syn::Data::Struct(syn::DataStruct { - fields: syn::Fields::Named(fields), - .. - }) = data - else { - return quote_spanned! { ident.span() => - compile_error!("Codec can only be derived for structs with named fields"); - } - .into(); - }; - let fields = fields.named; - - if fields.is_empty() { - return quote_spanned! { ident.span() => - compile_error!("Codec can only be derived for structs with at least one field"); - } - .into(); - } - - if let Some(unamed_field) = fields.iter().find(|f| f.ident.is_none()) { - return quote_spanned! { unamed_field.ty.span() => - compile_error!("Codec can only be derived for structs with named fields"); - } - .into(); - } - - let fields_ty: Vec<_> = fields.iter().map(|f| &f.ty).collect(); - let fields_ident: Vec<_> = fields - .iter() - .map(|f| f.ident.as_ref().expect("None case checked above")) - .collect(); - let fields_name_lit: Vec<_> = fields_ident - .iter() - .map(|i| LitStr::new(&i.to_string(), i.span())) - .collect(); - - let evm_data_trait_path = { - let mut segments = Punctuated::::new(); - segments.push(Ident::new("precompile_utils", Span::call_site()).into()); - segments.push(Ident::new("solidity", Span::call_site()).into()); - segments.push(Ident::new("Codec", Span::call_site()).into()); - Path { - leading_colon: Some(Default::default()), - segments, - } - }; - let where_clause = generics.make_where_clause(); - - for ty in &fields_ty { - let mut bounds = Punctuated::new(); - bounds.push( - TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path: evm_data_trait_path.clone(), - } - .into(), - ); - - where_clause.predicates.push( - PredicateType { - lifetimes: None, - bounded_ty: (*ty).clone(), - colon_token: Default::default(), - bounds, - } - .into(), - ); - } - - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - quote! { - impl #impl_generics ::precompile_utils::solidity::codec::Codec for #ident #ty_generics - #where_clause { - fn read( - reader: &mut ::precompile_utils::solidity::codec::Reader - ) -> ::precompile_utils::solidity::revert::MayRevert { - use ::precompile_utils::solidity::revert::BacktraceExt as _; - let (#(#fields_ident,)*): (#(#fields_ty,)*) = reader - .read() - .map_in_tuple_to_field(&[#(#fields_name_lit),*])?; - Ok(Self { - #(#fields_ident,)* - }) - } - - fn write(writer: &mut ::precompile_utils::solidity::codec::Writer, value: Self) { - ::precompile_utils::solidity::codec::Codec::write(writer, (#(value.#fields_ident,)*)); - } - - fn has_static_size() -> bool { - <(#(#fields_ty,)*)>::has_static_size() - } - - fn signature() -> String { - <(#(#fields_ty,)*)>::signature() - } - } - } - .into() -} diff --git a/precompiles/utils/macro/src/generate_function_selector.rs b/precompiles/utils/macro/src/generate_function_selector.rs deleted file mode 100644 index 7b0a62e1ce..0000000000 --- a/precompiles/utils/macro/src/generate_function_selector.rs +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; - -pub fn main(_: TokenStream, input: TokenStream) -> TokenStream { - let item = parse_macro_input!(input as ItemEnum); - - let ItemEnum { - attrs, - vis, - enum_token, - ident, - variants, - .. - } = item; - - let mut ident_expressions: Vec = vec![]; - let mut variant_expressions: Vec = vec![]; - let mut variant_attrs: Vec> = vec![]; - for variant in variants { - match variant.discriminant { - Some((_, Expr::Lit(ExprLit { lit, .. }))) => { - if let Lit::Str(lit_str) = lit { - let digest = Keccak256::digest(lit_str.value().as_bytes()); - let selector = u32::from_be_bytes([digest[0], digest[1], digest[2], digest[3]]); - ident_expressions.push(variant.ident); - variant_expressions.push(Expr::Lit(ExprLit { - lit: Lit::Verbatim(Literal::u32_suffixed(selector)), - attrs: Default::default(), - })); - variant_attrs.push(variant.attrs); - } else { - return quote_spanned! { - lit.span() => compile_error!("Expected literal string"); - } - .into(); - } - } - Some((_eg, expr)) => { - return quote_spanned! { - expr.span() => compile_error!("Expected literal"); - } - .into() - } - None => { - return quote_spanned! { - variant.span() => compile_error!("Each variant must have a discriminant"); - } - .into() - } - } - } - - (quote! { - #(#attrs)* - #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] - #[repr(u32)] - #vis #enum_token #ident { - #( - #(#variant_attrs)* - #ident_expressions = #variant_expressions, - )* - } - }) - .into() -} diff --git a/precompiles/utils/macro/src/lib.rs b/precompiles/utils/macro/src/lib.rs deleted file mode 100644 index 0b595ca042..0000000000 --- a/precompiles/utils/macro/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#![crate_type = "proc-macro"] -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::{quote, quote_spanned}; -use sp_core_hashing::keccak_256; -use syn::{parse_macro_input, spanned::Spanned, Expr, Ident, ItemType, Lit, LitStr}; - -mod derive_codec; -mod precompile; -mod precompile_name_from_address; - -struct Bytes(Vec); - -impl ::std::fmt::Debug for Bytes { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result { - let data = &self.0; - write!(f, "[")?; - if !data.is_empty() { - write!(f, "{:#04x}u8", data[0])?; - for unit in data.iter().skip(1) { - write!(f, ", {:#04x}", unit)?; - } - } - write!(f, "]") - } -} - -#[proc_macro] -pub fn keccak256(input: TokenStream) -> TokenStream { - let lit_str = parse_macro_input!(input as LitStr); - - let hash = keccak_256(lit_str.value().as_bytes()); - - let bytes = Bytes(hash.to_vec()); - let eval_str = format!("{:?}", bytes); - let eval_ts: proc_macro2::TokenStream = eval_str.parse().unwrap_or_else(|_| { - panic!( - "Failed to parse the string \"{}\" to TokenStream.", - eval_str - ); - }); - quote!(#eval_ts).into() -} - -#[proc_macro_attribute] -pub fn precompile(attr: TokenStream, input: TokenStream) -> TokenStream { - precompile::main(attr, input) -} - -#[proc_macro_attribute] -pub fn precompile_name_from_address(attr: TokenStream, input: TokenStream) -> TokenStream { - precompile_name_from_address::main(attr, input) -} - -#[proc_macro_derive(Codec)] -pub fn derive_codec(input: TokenStream) -> TokenStream { - derive_codec::main(input) -} diff --git a/precompiles/utils/macro/src/precompile/attr.rs b/precompiles/utils/macro/src/precompile/attr.rs deleted file mode 100644 index d7c7a459f5..0000000000 --- a/precompiles/utils/macro/src/precompile/attr.rs +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use proc_macro2::Span; -use quote::ToTokens; -use syn::spanned::Spanned; - -pub fn take_attributes(attributes: &mut Vec) -> syn::Result> -where - A: syn::parse::Parse, -{ - let mut output = vec![]; - let pred = |attr: &syn::Attribute| { - attr.path - .segments - .first() - .map_or(false, |segment| segment.ident == "precompile") - }; - - while let Some(index) = attributes.iter().position(pred) { - let attr = attributes.remove(index); - let attr = syn::parse2(attr.into_token_stream())?; - output.push(attr) - } - Ok(output) -} - -/// List of additional token to be used for parsing. -pub mod keyword { - syn::custom_keyword!(precompile); - syn::custom_keyword!(public); - syn::custom_keyword!(fallback); - syn::custom_keyword!(payable); - syn::custom_keyword!(view); - syn::custom_keyword!(discriminant); - syn::custom_keyword!(precompile_set); - syn::custom_keyword!(test_concrete_types); - syn::custom_keyword!(pre_check); -} - -/// Attributes for methods. -pub enum MethodAttr { - Public(Span, syn::LitStr), - Fallback(Span), - Payable(Span), - View(Span), - Discriminant(Span), - PreCheck(Span), -} - -impl syn::parse::Parse for MethodAttr { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; - - let lookahead = content.lookahead1(); - - if lookahead.peek(keyword::public) { - let span = content.parse::()?.span(); - - let inner; - syn::parenthesized!(inner in content); - let signature = inner.parse::()?; - - Ok(MethodAttr::Public(span, signature)) - } else if lookahead.peek(keyword::fallback) { - Ok(MethodAttr::Fallback( - content.parse::()?.span(), - )) - } else if lookahead.peek(keyword::payable) { - Ok(MethodAttr::Payable( - content.parse::()?.span(), - )) - } else if lookahead.peek(keyword::view) { - Ok(MethodAttr::View(content.parse::()?.span())) - } else if lookahead.peek(keyword::discriminant) { - Ok(MethodAttr::Discriminant( - content.parse::()?.span(), - )) - } else if lookahead.peek(keyword::pre_check) { - Ok(MethodAttr::PreCheck( - content.parse::()?.span(), - )) - } else { - Err(lookahead.error()) - } - } -} - -/// Attributes for the main impl Block. -pub enum ImplAttr { - PrecompileSet(Span), - TestConcreteTypes(Span, Vec), -} - -impl syn::parse::Parse for ImplAttr { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; - - let lookahead = content.lookahead1(); - - if lookahead.peek(keyword::precompile_set) { - Ok(ImplAttr::PrecompileSet( - content.parse::()?.span(), - )) - } else if lookahead.peek(keyword::test_concrete_types) { - let span = content.parse::()?.span(); - - let inner; - syn::parenthesized!(inner in content); - let types = inner.parse_terminated::<_, syn::Token![,]>(syn::Type::parse)?; - - Ok(ImplAttr::TestConcreteTypes( - span, - types.into_iter().collect(), - )) - } else { - Err(lookahead.error()) - } - } -} diff --git a/precompiles/utils/macro/src/precompile/expand.rs b/precompiles/utils/macro/src/precompile/expand.rs deleted file mode 100644 index aed4fce127..0000000000 --- a/precompiles/utils/macro/src/precompile/expand.rs +++ /dev/null @@ -1,527 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; - -impl Precompile { - /// Main expand function, which expands everything else. - pub fn expand(&self) -> impl ToTokens { - let enum_ = self.expand_enum_decl(); - let enum_impl = self.expand_enum_impl(); - let precomp_impl = self.expand_precompile_impl(); - let test_signature = self.expand_test_solidity_signature(); - - quote! { - #enum_ - #enum_impl - #precomp_impl - #test_signature - } - } - - /// Expands the call enum declaration. - pub fn expand_enum_decl(&self) -> impl ToTokens { - let enum_ident = &self.enum_ident; - let (_impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); - - let type_parameters = self.generics.type_params().map(|p| &p.ident); - - let variants: Vec<_> = self.variants_content.keys().collect(); - let idents: Vec> = self - .variants_content - .values() - .map(|v| v.arguments.iter().map(|a| &a.ident).collect()) - .collect(); - let types: Vec> = self - .variants_content - .values() - .map(|v| v.arguments.iter().map(|a| &a.ty).collect()) - .collect(); - - quote!( - #[allow(non_camel_case_types)] - pub enum #enum_ident #ty_generics #where_clause { - #( - #variants { - #( - #idents: #types - ),* - }, - )* - - #[doc(hidden)] - __phantom( - ::core::marker::PhantomData<( #( #type_parameters ),* )>, - ::core::convert::Infallible - ), - } - ) - } - - /// Expands the parse function for each variants. - pub fn expand_variants_parse_fn(&self) -> impl ToTokens { - let span = Span::call_site(); - - let fn_parse = self - .variants_content - .keys() - .map(Self::variant_ident_to_parse_fn); - - let modifier_check = self.variants_content.values().map(|variant| { - let modifier = match variant.modifier { - Modifier::NonPayable => "NonPayable", - Modifier::Payable => "Payable", - Modifier::View => "View", - }; - - let modifier = syn::Ident::new(modifier, span); - - quote!( - use ::precompile_utils::solidity::modifier::FunctionModifier; - use ::precompile_utils::evm::handle::PrecompileHandleExt; - handle.check_function_modifier(FunctionModifier::#modifier)?; - ) - }); - - let variant_parsing = self - .variants_content - .iter() - .map(|(variant_ident, variant)| { - Self::expand_variant_parsing_from_handle(variant_ident, variant) - }); - - quote!( - #( - fn #fn_parse( - handle: &mut impl PrecompileHandle - ) -> ::precompile_utils::EvmResult { - use ::precompile_utils::solidity::revert::InjectBacktrace; - - #modifier_check - #variant_parsing - } - )* - ) - } - - /// Generates the parsing code for a variant, reading the input from the handle and - /// parsing it using Reader. - fn expand_variant_parsing_from_handle( - variant_ident: &syn::Ident, - variant: &Variant, - ) -> impl ToTokens { - if variant.arguments.is_empty() { - quote!( Ok(Self::#variant_ident {})).to_token_stream() - } else { - use case::CaseExt; - - let args_parse = variant.arguments.iter().map(|arg| { - let ident = &arg.ident; - let span = ident.span(); - let name = ident.to_string().to_camel_lowercase(); - - quote_spanned!(span=> #ident: input.read().in_field(#name)?,) - }); - let args_count = variant.arguments.len(); - - quote!( - let mut input = handle.read_after_selector()?; - input.expect_arguments(#args_count)?; - - Ok(Self::#variant_ident { - #(#args_parse)* - }) - ) - .to_token_stream() - } - } - - /// Expands the call enum impl block. - pub fn expand_enum_impl(&self) -> impl ToTokens { - let enum_ident = &self.enum_ident; - let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); - - let match_selectors = self.selector_to_variant.keys(); - let match_selectors2 = self.selector_to_variant.keys(); - - let variants_parsing = self.expand_variants_parse_fn(); - - let variants_ident2: Vec<_> = self.variants_content.keys().collect(); - let variants_selectors_fn: Vec<_> = self - .variants_content - .keys() - .map(|name| format_ident!("{}_selectors", name)) - .collect(); - let variants_selectors: Vec<_> = self - .variants_content - .values() - .map(|variant| &variant.selectors) - .collect(); - - let variants_list: Vec> = self - .variants_content - .values() - .map(|variant| variant.arguments.iter().map(|arg| &arg.ident).collect()) - .collect(); - - let variants_encode: Vec<_> = self - .variants_content - .values() - .map(Self::expand_variant_encoding) - .collect(); - - let parse_call_data_fn = self.expand_enum_parse_call_data(); - let execute_fn = self.expand_enum_execute_fn(); - - quote!( - impl #impl_generics #enum_ident #ty_generics #where_clause { - #parse_call_data_fn - - #variants_parsing - - #execute_fn - - pub fn supports_selector(selector: u32) -> bool { - match selector { - #( - #match_selectors => true, - )* - _ => false, - } - } - - pub fn selectors() -> &'static [u32] { - &[#( - #match_selectors2 - ),*] - } - - #( - pub fn #variants_selectors_fn() -> &'static [u32] { - &[#( - #variants_selectors - ),*] - } - )* - - pub fn encode(self) -> ::sp_std::vec::Vec { - use ::precompile_utils::solidity::codec::Writer; - match self { - #( - Self::#variants_ident2 { #(#variants_list),* } => { - #variants_encode - }, - )* - Self::__phantom(_, _) => panic!("__phantom variant should not be used"), - } - } - } - - impl #impl_generics From<#enum_ident #ty_generics> for ::sp_std::vec::Vec - #where_clause - { - fn from(a: #enum_ident #ty_generics) -> ::sp_std::vec::Vec { - a.encode() - } - } - ) - } - - /// Expand the execute fn of the enum. - fn expand_enum_execute_fn(&self) -> impl ToTokens { - let impl_type = &self.impl_type; - - let variants_ident: Vec<_> = self.variants_content.keys().collect(); - - let variants_arguments: Vec> = self - .variants_content - .values() - .map(|variant| variant.arguments.iter().map(|arg| &arg.ident).collect()) - .collect(); - - // If there is no precompile set there is no discriminant. - let opt_discriminant_arg = self - .precompile_set_discriminant_type - .as_ref() - .map(|ty| quote!( discriminant: #ty,)); - - let variants_call = self - .variants_content - .iter() - .map(|(variant_ident, variant)| { - let arguments = variant.arguments.iter().map(|arg| &arg.ident); - - let output_span = variant.fn_output.span(); - let opt_discriminant_arg = self - .precompile_set_discriminant_fn - .as_ref() - .map(|_| quote!(discriminant,)); - - let write_output = quote_spanned!(output_span=> - ::precompile_utils::solidity::encode_return_value(output?) - ); - - quote!( - let output = <#impl_type>::#variant_ident( - #opt_discriminant_arg - handle, - #(#arguments),* - ); - #write_output - ) - }); - - quote!( - pub fn execute( - self, - #opt_discriminant_arg - handle: &mut impl PrecompileHandle - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - use ::precompile_utils::solidity::codec::Writer; - use ::fp_evm::{PrecompileOutput, ExitSucceed}; - - let output = match self { - #( - Self::#variants_ident { #(#variants_arguments),* } => { - #variants_call - }, - )* - Self::__phantom(_, _) => panic!("__phantom variant should not be used"), - }; - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output - }) - } - ) - } - - /// Expand how a variant can be Solidity encoded. - fn expand_variant_encoding(variant: &Variant) -> impl ToTokens { - match variant.selectors.first() { - Some(selector) => { - let write_arguments = variant.arguments.iter().map(|arg| { - let ident = &arg.ident; - let span = ident.span(); - quote_spanned!(span=> .write(#ident)) - }); - - quote!( - Writer::new_with_selector(#selector) - #(#write_arguments)* - .build() - ) - .to_token_stream() - } - None => quote!(Default::default()).to_token_stream(), - } - } - - /// Expand the main parsing function that, based on the selector in the - /// input, dispatch the decoding to one of the variants parsing function. - fn expand_enum_parse_call_data(&self) -> impl ToTokens { - let selectors = self.selector_to_variant.keys(); - let parse_fn = self - .selector_to_variant - .values() - .map(Self::variant_ident_to_parse_fn); - - let match_fallback = match &self.fallback_to_variant { - Some(variant) => { - let parse_fn = Self::variant_ident_to_parse_fn(variant); - quote!(_ => Self::#parse_fn(handle),).to_token_stream() - } - None => quote!( - Some(_) => Err(RevertReason::UnknownSelector.into()), - None => Err(RevertReason::read_out_of_bounds("selector").into()), - ) - .to_token_stream(), - }; - - quote!( - pub fn parse_call_data( - handle: &mut impl PrecompileHandle - ) -> ::precompile_utils::EvmResult { - use ::precompile_utils::solidity::revert::RevertReason; - - let input = handle.input(); - - let selector = input.get(0..4).map(|s| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(s); - u32::from_be_bytes(buffer) - }); - - match selector { - #( - Some(#selectors) => Self::#parse_fn(handle), - )* - #match_fallback - } - } - ) - } - - fn variant_ident_to_parse_fn(ident: &syn::Ident) -> syn::Ident { - format_ident!("_parse_{}", ident) - } - - /// Expands the impl of the Precomile(Set) trait. - pub fn expand_precompile_impl(&self) -> impl ToTokens { - let impl_type = &self.impl_type; - let enum_ident = &self.enum_ident; - let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); - - if let Some(discriminant_fn) = &self.precompile_set_discriminant_fn { - let opt_pre_check = self.pre_check.as_ref().map(|ident| { - let span = ident.span(); - quote_spanned!(span=> - let _: () = <#impl_type>::#ident(discriminant, handle) - .map_err(|err| Some(err))?; - ) - }); - - quote!( - impl #impl_generics ::fp_evm::PrecompileSet for #impl_type #where_clause { - fn execute( - &self, - handle: &mut impl PrecompileHandle - ) -> Option<::precompile_utils::EvmResult<::fp_evm::PrecompileOutput>> { - use ::precompile_utils::precompile_set::DiscriminantResult; - - let discriminant = <#impl_type>::#discriminant_fn( - handle.code_address(), - handle.remaining_gas() - ); - - if let DiscriminantResult::Some(_, cost) | DiscriminantResult::None(cost) = discriminant { - let result = handle.record_cost(cost); - if let Err(e) = result { - return Some(Err(e.into())); - } - } - - let discriminant = match discriminant { - DiscriminantResult::Some(d, _) => d, - DiscriminantResult::None(cost) => return None, - DiscriminantResult::OutOfGas => return Some(Err(ExitError::OutOfGas.into())) - }; - - #opt_pre_check - - Some( - <#enum_ident #ty_generics>::parse_call_data(handle) - .and_then(|call| call.execute(discriminant, handle)) - ) - } - - fn is_precompile(&self, address: H160, gas: u64) -> ::fp_evm::IsPrecompileResult { - <#impl_type>::#discriminant_fn(address, gas).into() - } - } - ) - .to_token_stream() - } else { - let opt_pre_check = self.pre_check.as_ref().map(|ident| { - let span = ident.span(); - quote_spanned!(span=>let _: () = <#impl_type>::#ident(handle)?;) - }); - - quote!( - impl #impl_generics ::fp_evm::Precompile for #impl_type #where_clause { - fn execute( - handle: &mut impl PrecompileHandle - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - #opt_pre_check - - <#enum_ident #ty_generics>::parse_call_data(handle)?.execute(handle) - } - } - ) - .to_token_stream() - } - } - - /// Expands the Solidity signature test. - /// The macro expands an "inner" function in all build profiles, which is - /// then called by a test in test profile. This allows to display errors that occurs in - /// the expansion of the test without having to build in test profile, which is usually - /// related to the use of a type parameter in one of the parsed parameters of a method. - pub fn expand_test_solidity_signature(&self) -> impl ToTokens { - let variant_test: Vec<_> = self - .variants_content - .iter() - .map(|(ident, variant)| { - let span = ident.span(); - - let solidity = &variant.solidity_arguments_type; - let name = ident.to_string(); - let types: Vec<_> = variant.arguments.iter().map(|arg| &arg.ty).collect(); - - quote_spanned!(span=> - assert_eq!( - #solidity, - <(#(#types,)*) as Codec>::signature(), - "{} function signature doesn't match (left: attribute, right: computed \ - from Rust types)", - #name - ); - ) - }) - .collect(); - - let test_name = format_ident!("__{}_test_solidity_signatures", self.impl_ident); - let inner_name = format_ident!("__{}_test_solidity_signatures_inner", self.impl_ident); - - if let Some(test_types) = &self.test_concrete_types { - let (impl_generics, _ty_generics, where_clause) = self.generics.split_for_impl(); - - quote!( - #[allow(non_snake_case)] - pub(crate) fn #inner_name #impl_generics () #where_clause { - use ::precompile_utils::solidity::Codec; - #(#variant_test)* - } - - #[test] - #[allow(non_snake_case)] - fn #test_name() { - #inner_name::< #(#test_types),* >(); - } - ) - .to_token_stream() - } else { - quote!( - #[allow(non_snake_case)] - pub(crate) fn #inner_name() { - use ::precompile_utils::solidity::Codec; - #(#variant_test)* - } - - #[test] - #[allow(non_snake_case)] - fn #test_name() { - #inner_name(); - } - ) - .to_token_stream() - } - } -} diff --git a/precompiles/utils/macro/src/precompile/mod.rs b/precompiles/utils/macro/src/precompile/mod.rs deleted file mode 100644 index 2c8ac1df8e..0000000000 --- a/precompiles/utils/macro/src/precompile/mod.rs +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#![doc = include_str!("../../docs/precompile_macro.md")] - -use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{format_ident, quote, quote_spanned, ToTokens}; -use sp_core_hashing::keccak_256; -use std::collections::BTreeMap; -use syn::{parse_macro_input, spanned::Spanned}; - -pub mod attr; -pub mod expand; -pub mod parse; - -pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream { - // Macro must be used on `impl` block. - let mut impl_item = parse_macro_input!(item as syn::ItemImpl); - - // We inspect the block to collect all the data we need for the - // expansion, and make various checks. - let precompile = match Precompile::try_from(&mut impl_item) { - Ok(p) => p, - Err(e) => return e.into_compile_error().into(), - }; - - // We generate additional code based on the collected data. - let new_items = precompile.expand(); - let output = quote!( - #impl_item - #new_items - ); - - output.into() -} - -struct Precompile { - /// Impl struct type. - impl_type: syn::Type, - - /// Impl struct ident. - impl_ident: syn::Ident, - - /// New parsing enum ident. - enum_ident: syn::Ident, - - /// Generic part that needs to also be used by the input enum. - generics: syn::Generics, - - /// Which selector corresponds to which variant of the input enum. - selector_to_variant: BTreeMap, - - /// Optional fallback function if no selector matches. - fallback_to_variant: Option, - - /// Describes the content of each variant based on the precompile methods. - variants_content: BTreeMap, - - /// Since being a precompile set implies lots of changes, we must know it early - /// in the form of an attribute on the impl block itself. - tagged_as_precompile_set: bool, - - /// Ident of the function returning the PrecompileSet discriminant. - precompile_set_discriminant_fn: Option, - - /// Type of the PrecompileSet discriminant. - precompile_set_discriminant_type: Option, - - /// When generating the selector test the data types might depend on type parameters. - /// The test thus need to be written using concrete types. - test_concrete_types: Option>, - - /// Ident of a function that performs a check before the call is dispatched to the proper - /// function. - pre_check: Option, -} - -#[derive(Debug, PartialEq, Eq)] -enum Modifier { - NonPayable, - Payable, - View, -} - -#[derive(Debug)] -struct Variant { - /// Description of the arguments of this method, which will also - /// be members of a struct variant. - arguments: Vec, - - /// String extracted from the selector attribute. - /// A unit test will be generated to check that this selector matches - /// the Rust arguments. - /// - /// > solidity::Codec trait allows to generate this string at runtime only. Thus - /// > it is required to write it manually in the selector attribute, and - /// > a unit test is generated to check it matches. - solidity_arguments_type: String, - - /// Modifier of the function. They are all exclusive and defaults to - /// `NonPayable`. - modifier: Modifier, - - /// Selectors of this function to be able to encode back the data. - /// Empty if it only the fallback function. - selectors: Vec, - - /// Output of the variant fn (for better error messages). - fn_output: syn::Type, -} - -#[derive(Debug)] -struct Argument { - /// Identifier of the argument, which will be used in the struct variant. - ident: syn::Ident, - - /// Type of the argument, which will be used in the struct variant and - /// to parse the input. - ty: syn::Type, -} diff --git a/precompiles/utils/macro/src/precompile/parse.rs b/precompiles/utils/macro/src/precompile/parse.rs deleted file mode 100644 index a41a1ba650..0000000000 --- a/precompiles/utils/macro/src/precompile/parse.rs +++ /dev/null @@ -1,628 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; - -impl Precompile { - /// Try to extract information out of an annotated `impl` block. - pub fn try_from(impl_: &mut syn::ItemImpl) -> syn::Result { - // Extract the name of the type used in the `impl` block. - let impl_ident = Self::extract_impl_ident(impl_)?; - let enum_ident = format_ident!("{}Call", impl_ident); - - // We setup the data collection struct. - let mut precompile = Precompile { - impl_type: impl_.self_ty.as_ref().clone(), - impl_ident, - enum_ident, - generics: impl_.generics.clone(), - selector_to_variant: BTreeMap::new(), - variants_content: BTreeMap::new(), - fallback_to_variant: None, - tagged_as_precompile_set: false, - precompile_set_discriminant_fn: None, - precompile_set_discriminant_type: None, - test_concrete_types: None, - pre_check: None, - }; - - precompile.process_impl_attr(impl_)?; - for mut item in &mut impl_.items { - // We only interact with methods and leave the rest as-is. - if let syn::ImplItem::Method(ref mut method) = &mut item { - precompile.process_method(method)?; - } - } - - // Check constraint of PrecompileSet. - if precompile.tagged_as_precompile_set - && precompile.precompile_set_discriminant_fn.is_none() - { - let msg = "A PrecompileSet must have exactly one function tagged with \ - `#[precompile::discriminant]`"; - return Err(syn::Error::new(Span::call_site(), msg)); - } - - Ok(precompile) - } - - /// Process the attributes used on the `impl` block, which allows to declare - /// if it is a PrecompileSet or not, and to provide concrete types for tests if necessary. - fn process_impl_attr(&mut self, impl_: &mut syn::ItemImpl) -> syn::Result<()> { - let attrs = attr::take_attributes::(&mut impl_.attrs)?; - - for attr in attrs { - match attr { - attr::ImplAttr::PrecompileSet(_) => { - self.tagged_as_precompile_set = true; - } - attr::ImplAttr::TestConcreteTypes(span, types) => { - if types.len() != self.generics.params.len() { - let msg = "The amount of types should match the amount of type parameters \ - of the impl block"; - return Err(syn::Error::new(span, msg)); - } - - if self.test_concrete_types.is_some() { - let msg = "Only one set of types can be provided to generate tests"; - return Err(syn::Error::new(span, msg)); - } - - self.test_concrete_types = Some(types); - } - } - } - - Ok(()) - } - - /// Extract the ident of the type of the `impl` block. - /// This ident is used to generate new idents such as the name of the Call enum and - /// the Solidity selector test. - fn extract_impl_ident(impl_: &syn::ItemImpl) -> syn::Result { - let type_path = match impl_.self_ty.as_ref() { - syn::Type::Path(p) => p, - _ => { - let msg = "The type in the impl block must be a path, like `Precompile` or - `example::Precompile`"; - return Err(syn::Error::new(impl_.self_ty.span(), msg)); - } - }; - - let final_path = type_path.path.segments.last().ok_or_else(|| { - let msg = "The type path must be non empty."; - syn::Error::new(impl_.self_ty.span(), msg) - })?; - - Ok(final_path.ident.clone()) - } - - /// Process a single method, looking for attributes and checking mandatory parameters. - fn process_method(&mut self, method: &mut syn::ImplItemMethod) -> syn::Result<()> { - // Take (remove) all attributes related to this macro. - let attrs = attr::take_attributes::(&mut method.attrs)?; - - // If there are no attributes it is a private function and we ignore it. - if attrs.is_empty() { - return Ok(()); - } - - // A method cannot have modifiers if it isn't a fallback and/or doesn't have a selector. - let mut used = false; - - let method_name = method.sig.ident.clone(); - let mut modifier = Modifier::NonPayable; - let mut solidity_arguments_type: Option = None; - let mut arguments = vec![]; - let mut is_fallback = false; - let mut selectors = vec![]; - let initial_arguments = if self.tagged_as_precompile_set { 2 } else { 1 }; - - // We first look for unique attributes. - if let Some(attr::MethodAttr::Discriminant(span)) = attrs.first() { - let span = *span; - - if attrs.len() != 1 { - let msg = "The discriminant attribute must be the only precompile attribute of \ - a function"; - return Err(syn::Error::new(span, msg)); - } - - return self.parse_discriminant_fn(span, method); - } - - if let Some(attr::MethodAttr::PreCheck(span)) = attrs.first() { - let span = *span; - - if attrs.len() != 1 { - let msg = "The pre_check attribute must be the only precompile attribute of \ - a function"; - return Err(syn::Error::new(span, msg)); - } - - return self.parse_pre_check_fn(span, method); - } - - // We iterate over all attributes of the method. - for attr in attrs { - match attr { - attr::MethodAttr::Discriminant(span) => { - let msg = "The discriminant attribute must be the only precompile \ - attribute of the function"; - return Err(syn::Error::new(span, msg)); - } - attr::MethodAttr::PreCheck(span) => { - let msg = "The pre_check attribute must be the only precompile \ - attribute of the function"; - return Err(syn::Error::new(span, msg)); - } - attr::MethodAttr::Fallback(span) => { - if self.fallback_to_variant.is_some() { - let msg = "A precompile can only have 1 fallback function"; - return Err(syn::Error::new(span, msg)); - } - - self.fallback_to_variant = Some(method_name.clone()); - used = true; - is_fallback = true; - } - attr::MethodAttr::Payable(span) => { - if modifier != Modifier::NonPayable { - let msg = - "A precompile method can have at most one modifier (payable, view)"; - return Err(syn::Error::new(span, msg)); - } - - modifier = Modifier::Payable; - } - attr::MethodAttr::View(span) => { - if modifier != Modifier::NonPayable { - let msg = - "A precompile method can have at most one modifier (payable, view)"; - return Err(syn::Error::new(span, msg)); - } - - modifier = Modifier::View; - } - attr::MethodAttr::Public(_, signature_lit) => { - used = true; - - let selector = self.parse_public_attr( - signature_lit, - &method_name, - &mut solidity_arguments_type, - )?; - selectors.push(selector); - } - } - } - - // A method cannot have attributes without being public or fallback. - if !used { - let msg = - "A precompile method cannot have modifiers without being a fallback or having\ - a `public` attribute"; - return Err(syn::Error::new(method.span(), msg)); - } - - // We forbid type parameters. - if let Some(param) = method.sig.generics.params.first() { - let msg = "Exposed precompile methods cannot have type parameters"; - return Err(syn::Error::new(param.span(), msg)); - } - - // Fallback method cannot have custom parameters. - if is_fallback { - if let Some(input) = method.sig.inputs.iter().nth(initial_arguments) { - let msg = if self.tagged_as_precompile_set { - "Fallback methods cannot take any parameter outside of the discriminant and \ - PrecompileHandle" - } else { - "Fallback methods cannot take any parameter outside of the PrecompileHandle" - }; - - return Err(syn::Error::new(input.span(), msg)); - } - } - - let mut method_inputs = method.sig.inputs.iter(); - - // We check the first parameters of the method. - // If this is a PrecompileSet it will look for a discriminant. - // Then for all precompile(set)s it will look for the PrecompileHandle. - // We take them from the iterator such that we are only left with the - // custom arguments. - self.check_initial_parameters(&mut method_inputs, method.sig.span())?; - - // We go through each parameter to collect each name and type that will be used to - // generate the input enum and parse the call data. - for input in method_inputs { - let input = match input { - syn::FnArg::Typed(t) => t, - _ => { - // I don't think it is possible to encounter this error since a self receiver - // seems to only be possible in the first position which is checked in - // `check_initial_parameters`. - let msg = "Exposed precompile methods cannot have a `self` parameter"; - return Err(syn::Error::new(input.span(), msg)); - } - }; - - let msg = "Parameter must be of the form `name: Type`, optionally prefixed by `mut`"; - let ident = match input.pat.as_ref() { - syn::Pat::Ident(pat) => { - if pat.by_ref.is_some() || pat.subpat.is_some() { - return Err(syn::Error::new(pat.span(), msg)); - } - - pat.ident.clone() - } - _ => { - return Err(syn::Error::new(input.pat.span(), msg)); - } - }; - let ty = input.ty.as_ref().clone(); - self.check_type_parameter_usage(&ty)?; - - arguments.push(Argument { ident, ty }) - } - - // Function output. - let output_type = match &method.sig.output { - syn::ReturnType::Type(_, t) => t, - _ => { - let msg = "A precompile method must have a return type of `EvmResult<_>` (exposed \ - by `precompile_utils`)"; - return Err(syn::Error::new(method.sig.span(), msg)); - } - }; - - // We insert the collected data in self. - if self - .variants_content - .insert( - method_name.clone(), - Variant { - arguments, - solidity_arguments_type: solidity_arguments_type.unwrap_or(String::from("()")), - modifier, - selectors, - fn_output: output_type.as_ref().clone(), - }, - ) - .is_some() - { - let msg = "Duplicate method name"; - return Err(syn::Error::new(method_name.span(), msg)); - } - - Ok(()) - } - - /// Check the initial parameters of most methods of a Precompile(Set). - fn check_initial_parameters<'a>( - &mut self, - method_inputs: &mut impl Iterator, - method_span: Span, - ) -> syn::Result<()> { - // Discriminant input - if self.tagged_as_precompile_set { - let input = match method_inputs.next() { - Some(a) => a, - None => { - let msg = "PrecompileSet methods must have at least 2 parameters (the \ - precompile instance discriminant and the PrecompileHandle)"; - return Err(syn::Error::new(method_span, msg)); - } - }; - - let input = match input { - syn::FnArg::Typed(a) => a, - _ => { - let msg = "self is not allowed in precompile methods"; - return Err(syn::Error::new(input.span(), msg)); - } - }; - - let input_type = input.ty.as_ref(); - - self.try_register_discriminant_type(input_type)?; - } - - // Precompile handle input - { - let input = match method_inputs.next() { - Some(a) => a, - None => { - let msg = if self.tagged_as_precompile_set { - "PrecompileSet methods must have at least 2 parameters (the precompile \ - instance discriminant and the PrecompileHandle)" - } else { - "Precompile methods must have at least 1 parameter (the PrecompileHandle)" - }; - - return Err(syn::Error::new(method_span, msg)); - } - }; - - let input = match input { - syn::FnArg::Typed(a) => a, - _ => { - let msg = "self is not allowed in precompile methods"; - return Err(syn::Error::new(input.span(), msg)); - } - }; - - let input_type = input.ty.as_ref(); - - if !is_same_type(input_type, &syn::parse_quote! {&mut impl PrecompileHandle}) { - let msg = "This parameter must have type `&mut impl PrecompileHandle`"; - return Err(syn::Error::new(input_type.span(), msg)); - } - } - - Ok(()) - } - - /// Records the type of the discriminant and ensure they all have the same type. - fn try_register_discriminant_type(&mut self, ty: &syn::Type) -> syn::Result<()> { - if let Some(known_type) = &self.precompile_set_discriminant_type { - if !is_same_type(known_type, ty) { - let msg = format!( - "All discriminants must have the same type (found {} before)", - known_type.to_token_stream() - ); - return Err(syn::Error::new(ty.span(), msg)); - } - } else { - self.precompile_set_discriminant_type = Some(ty.clone()); - } - - Ok(()) - } - - /// Process the discriminant function. - fn parse_discriminant_fn( - &mut self, - span: Span, - method: &syn::ImplItemMethod, - ) -> syn::Result<()> { - if !self.tagged_as_precompile_set { - let msg = "The impl block must be tagged with `#[precompile::precompile_set]` for - the discriminant attribute to be used"; - return Err(syn::Error::new(span, msg)); - } - - if self.precompile_set_discriminant_fn.is_some() { - let msg = "A PrecompileSet can only have 1 discriminant function"; - return Err(syn::Error::new(span, msg)); - } - - let span = method.sig.span(); - - if method.sig.inputs.len() != 2 { - let msg = "The discriminant function must only take code address (H160) and \ - remaining gas (u64) as parameters."; - return Err(syn::Error::new(span, msg)); - } - - let msg = "The discriminant function must return an DiscriminantResult<_> (no type alias)"; - - let return_type = match &method.sig.output { - syn::ReturnType::Type(_, t) => t.as_ref(), - _ => return Err(syn::Error::new(span, msg)), - }; - - let return_path = match return_type { - syn::Type::Path(p) => p, - _ => return Err(syn::Error::new(span, msg)), - }; - - if return_path.qself.is_some() { - return Err(syn::Error::new(span, msg)); - } - - let return_path = &return_path.path; - - if return_path.leading_colon.is_some() || return_path.segments.len() != 1 { - return Err(syn::Error::new(span, msg)); - } - - let return_segment = &return_path.segments[0]; - - if return_segment.ident != "DiscriminantResult" { - return Err(syn::Error::new(return_segment.ident.span(), msg)); - } - - let result_arguments = match &return_segment.arguments { - syn::PathArguments::AngleBracketed(args) => args, - _ => return Err(syn::Error::new(return_segment.ident.span(), msg)), - }; - - if result_arguments.args.len() != 1 { - let msg = "DiscriminantResult type should only have 1 type argument"; - return Err(syn::Error::new(result_arguments.args.span(), msg)); - } - - let discriminant_type: &syn::Type = match &result_arguments.args[0] { - syn::GenericArgument::Type(t) => t, - _ => return Err(syn::Error::new(result_arguments.args.span(), msg)), - }; - - self.try_register_discriminant_type(discriminant_type)?; - - self.precompile_set_discriminant_fn = Some(method.sig.ident.clone()); - - Ok(()) - } - - /// Process the pre_check function. - fn parse_pre_check_fn(&mut self, span: Span, method: &syn::ImplItemMethod) -> syn::Result<()> { - if self.pre_check.is_some() { - let msg = "A Precompile can only have 1 pre_check function"; - return Err(syn::Error::new(span, msg)); - } - - let span = method.sig.span(); - - let mut method_inputs = method.sig.inputs.iter(); - - self.check_initial_parameters(&mut method_inputs, span)?; - - if method_inputs.next().is_some() { - let msg = if self.tagged_as_precompile_set { - "PrecompileSet pre_check method must have exactly 2 parameters (the precompile \ - instance discriminant and the PrecompileHandle)" - } else { - "Precompile pre_check method must have exactly 1 parameter (the \ - PrecompileHandle)" - }; - - return Err(syn::Error::new(span, msg)); - } - - self.pre_check = Some(method.sig.ident.clone()); - - Ok(()) - } - - /// Process a `public` attribute on a method. - fn parse_public_attr( - &mut self, - signature_lit: syn::LitStr, - method_name: &syn::Ident, - solidity_arguments_type: &mut Option, - ) -> syn::Result { - let signature = signature_lit.value(); - // Split signature to get arguments type. - let split: Vec<_> = signature.splitn(2, '(').collect(); - if split.len() != 2 { - let msg = "Selector must have form \"foo(arg1,arg2,...)\""; - return Err(syn::Error::new(signature_lit.span(), msg)); - } - - let local_args_type = format!("({}", split[1]); // add back initial parenthesis - - // If there are multiple public attributes we check that they all have - // the same type. - if let Some(ref args_type) = solidity_arguments_type { - if args_type != &local_args_type { - let msg = "Method cannot have selectors with different types."; - return Err(syn::Error::new(signature_lit.span(), msg)); - } - } else { - *solidity_arguments_type = Some(local_args_type); - } - - // Compute the 4-bytes selector. - let digest = keccak_256(signature.as_bytes()); - let selector = u32::from_be_bytes([digest[0], digest[1], digest[2], digest[3]]); - - if let Some(previous) = self - .selector_to_variant - .insert(selector, method_name.clone()) - { - let msg = format!("Selector collision with method {previous}"); - return Err(syn::Error::new(signature_lit.span(), msg)); - } - - Ok(selector) - } - - /// Check that the provided type doesn't depend on one of the type parameters of the - /// precompile. Check is skipped if `test_concrete_types` attribute is used. - fn check_type_parameter_usage(&self, ty: &syn::Type) -> syn::Result<()> { - if self.test_concrete_types.is_some() { - return Ok(()); - } - - const ERR_MESSAGE: &str = - "impl type parameter is used in functions arguments. Arguments should not have a type -depending on a type parameter, unless it is a length bound for BoundedBytes, -BoundedString or alike, which doesn't affect the Solidity type. - -In that case, you must add a #[precompile::test_concrete_types(...)] attribute on the impl -block to provide concrete types that will be used to run the automatically generated tests -ensuring the Solidity function signatures are correct."; - - match ty { - syn::Type::Array(syn::TypeArray { elem, .. }) - | syn::Type::Group(syn::TypeGroup { elem, .. }) - | syn::Type::Paren(syn::TypeParen { elem, .. }) - | syn::Type::Reference(syn::TypeReference { elem, .. }) - | syn::Type::Ptr(syn::TypePtr { elem, .. }) - | syn::Type::Slice(syn::TypeSlice { elem, .. }) => { - self.check_type_parameter_usage(elem)? - } - - syn::Type::Path(syn::TypePath { - path: syn::Path { segments, .. }, - .. - }) => { - let impl_params: Vec<_> = self - .generics - .params - .iter() - .filter_map(|param| match param { - syn::GenericParam::Type(syn::TypeParam { ident, .. }) => Some(ident), - _ => None, - }) - .collect(); - - for segment in segments { - if impl_params.contains(&&segment.ident) { - return Err(syn::Error::new(segment.ident.span(), ERR_MESSAGE)); - } - - if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { - let types = args.args.iter().filter_map(|arg| match arg { - syn::GenericArgument::Type(ty) - | syn::GenericArgument::Binding(syn::Binding { ty, .. }) => Some(ty), - _ => None, - }); - - for ty in types { - self.check_type_parameter_usage(ty)?; - } - } - } - } - syn::Type::Tuple(tuple) => { - for ty in tuple.elems.iter() { - self.check_type_parameter_usage(ty)?; - } - } - // BareFn => very unlikely this appear as parameter - // ImplTrait => will cause other errors, it must be a concrete type - // TypeInfer => it must be explicit concrete types since it ends up in enum fields - // Macro => Cannot check easily - // Never => Function will not be callable. - ty => println!("Skipping type parameter check for non supported kind of type: {ty:?}"), - } - - Ok(()) - } -} - -/// Helper to check 2 types are equal. -/// Having a function with explicit type annotation helps type inference at callsite, -/// which have trouble if `==` is used inline. -fn is_same_type(a: &syn::Type, b: &syn::Type) -> bool { - a == b -} diff --git a/precompiles/utils/macro/src/precompile_name_from_address.rs b/precompiles/utils/macro/src/precompile_name_from_address.rs deleted file mode 100644 index 50da96e44a..0000000000 --- a/precompiles/utils/macro/src/precompile_name_from_address.rs +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; -use syn::{GenericArgument, Type}; - -pub fn main(_: TokenStream, input: TokenStream) -> TokenStream { - let item = parse_macro_input!(input as ItemType); - - let ItemType { - attrs, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } = item; - - if let Type::Tuple(ref type_tuple) = *ty { - let variants: Vec<(Ident, u64)> = type_tuple - .elems - .iter() - .filter_map(extract_precompile_name_and_prefix) - .collect(); - - let ident_expressions: Vec<&Ident> = variants.iter().map(|(ident, _)| ident).collect(); - let variant_expressions: Vec<&u64> = variants.iter().map(|(_, id)| id).collect(); - - (quote! { - #(#attrs)* - #vis #type_token #ident #generics #eq_token #ty #semi_token - - #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive, Debug)] - #[repr(u64)] - pub enum PrecompileName { - #( - #ident_expressions = #variant_expressions, - )* - } - - impl PrecompileName { - pub fn from_address(address: sp_core::H160) -> Option { - let _u64 = address.to_low_u64_be(); - if address == sp_core::H160::from_low_u64_be(_u64) { - use num_enum::TryFromPrimitive; - Self::try_from_primitive(_u64).ok() - } else { - None - } - } - } - }) - .into() - } else { - quote_spanned! { - ty.span() => compile_error!("Expected tuple"); - } - .into() - } -} - -fn extract_precompile_name_and_prefix(type_: &Type) -> Option<(Ident, u64)> { - match type_ { - Type::Path(type_path) => { - if let Some(path_segment) = type_path.path.segments.last() { - match path_segment.ident.to_string().as_ref() { - "PrecompileAt" => { - extract_precompile_name_and_prefix_for_precompile_at(path_segment) - } - _ => None, - } - } else { - None - } - } - _ => None, - } -} - -fn extract_precompile_name_and_prefix_for_precompile_at( - path_segment: &syn::PathSegment, -) -> Option<(Ident, u64)> { - if let syn::PathArguments::AngleBracketed(generics) = &path_segment.arguments { - let mut iter = generics.args.iter(); - if let ( - Some(GenericArgument::Type(Type::Path(type_path_1))), - Some(GenericArgument::Type(Type::Path(type_path_2))), - ) = (iter.next(), iter.next()) - { - if let (Some(path_segment_1), Some(path_segment_2)) = ( - type_path_1.path.segments.last(), - type_path_2.path.segments.last(), - ) { - if let syn::PathArguments::AngleBracketed(generics_) = &path_segment_1.arguments { - if let Some(GenericArgument::Const(Expr::Lit(lit))) = generics_.args.first() { - if let Lit::Int(int) = &lit.lit { - if let Ok(precompile_id) = int.base10_parse() { - if &path_segment_2.ident.to_string() == "CollectivePrecompile" { - if let Some(instance_ident) = - precompile_instance_ident(path_segment_2) - { - return Some((instance_ident, precompile_id)); - } - } else { - return Some((path_segment_2.ident.clone(), precompile_id)); - } - } - } - } - } - } - } - } - - None -} - -fn precompile_instance_ident(path_segment: &syn::PathSegment) -> Option { - if let syn::PathArguments::AngleBracketed(generics_) = &path_segment.arguments { - if let Some(GenericArgument::Type(Type::Path(instance_type_path))) = generics_.args.last() { - if let Some(instance_type) = instance_type_path.path.segments.last() { - return Some(instance_type.ident.clone()); - } - } - } - - None -} diff --git a/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.rs b/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.rs deleted file mode 100644 index 86bfbcaa32..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.rs +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use precompile_utils::prelude::*; - -#[derive(solidity::Codec)] -struct Empty1; - -#[derive(solidity::Codec)] -struct Empty2 {} - -#[derive(solidity::Codec)] -struct Empty3(); - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.stderr b/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.stderr deleted file mode 100644 index 8c0a9d8bae..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/derive_codec/empty_struct.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: Codec can only be derived for structs with named fields - --> tests/compile-fail/derive_codec/empty_struct.rs:20:8 - | -20 | struct Empty1; - | ^^^^^^ - -error: Codec can only be derived for structs with at least one field - --> tests/compile-fail/derive_codec/empty_struct.rs:23:8 - | -23 | struct Empty2 {} - | ^^^^^^ - -error: Codec can only be derived for structs with named fields - --> tests/compile-fail/derive_codec/empty_struct.rs:26:8 - | -26 | struct Empty3 (); - | ^^^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.rs b/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.rs deleted file mode 100644 index 76eb6740ee..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use precompile_utils::prelude::*; - -#[derive(solidity::Codec)] -enum Test { - One, - Two(u8), - Three { test: u16 }, -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.stderr b/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.stderr deleted file mode 100644 index 42a65d4a17..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/derive_codec/enum.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Codec can only be derived for structs with named fields - --> tests/compile-fail/derive_codec/enum.rs:20:6 - | -20 | enum Test { - | ^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs b/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs deleted file mode 100644 index 4fea235ac7..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use fp_evm::PrecompileHandle; -use precompile_utils::EvmResult; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.stderr deleted file mode 100644 index 1e87e3c771..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/arg-dont-impl-codec.stderr +++ /dev/null @@ -1,61 +0,0 @@ -error[E0277]: the trait bound `String: Codec` is not satisfied - --> tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs:26:43 - | -26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult { - | ^^^ the trait `Codec` is not implemented for `String` - | - = help: the following other types implement trait `Codec`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and $N others -note: required by a bound in `Reader::<'inner>::read` - --> $WORKSPACE/precompiles/utils/src/solidity/codec/mod.rs - | - | pub fn read(&mut self) -> MayRevert { - | ^^^^^ required by this bound in `Reader::<'inner>::read` - -error[E0277]: the trait bound `String: Codec` is not satisfied - --> tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs:26:43 - | -26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult { - | ^^^ the trait `Codec` is not implemented for `String` - | - = help: the following other types implement trait `Codec`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and $N others -note: required by a bound in `precompile_utils::solidity::codec::Writer::write` - --> $WORKSPACE/precompiles/utils/src/solidity/codec/mod.rs - | - | pub fn write(mut self, value: T) -> Self { - | ^^^^^ required by this bound in `Writer::write` - -error[E0277]: the trait bound `String: Codec` is not satisfied - --> tests/compile-fail/precompile/codec/arg-dont-impl-codec.rs:26:5 - | -26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult { - | ^^^ the trait `Codec` is not implemented for `String` - | - = help: the following other types implement trait `Codec`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and $N others - = note: required for `(String,)` to implement `Codec` diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.rs b/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.rs deleted file mode 100644 index a721ada56f..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(test: &mut impl PrecompileHandle) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.stderr deleted file mode 100644 index 7a2758d0f5..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/no-output.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: A precompile method must have a return type of `EvmResult<_>` (exposed by `precompile_utils`) - --> tests/compile-fail/precompile/codec/no-output.rs:24:2 - | -24 | fn foo(test: &mut impl PrecompileHandle) { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.rs b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.rs deleted file mode 100644 index ada7b05afa..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.rs +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use fp_evm::PrecompileHandle; -use precompile_utils::EvmResult; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.stderr deleted file mode 100644 index 52ba67e654..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-dont-impl-codec.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0277]: the trait bound `String: Codec` is not satisfied - --> tests/compile-fail/precompile/codec/output-dont-impl-codec.rs:26:46 - | -26 | fn foo(test: &mut impl PrecompileHandle) -> EvmResult { - | ^^^^^^^^^ the trait `Codec` is not implemented for `String` - | - = help: the following other types implement trait `Codec`: - () - (TupleElement0, TupleElement1) - (TupleElement0, TupleElement1, TupleElement2) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) - (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and $N others -note: required by a bound in `encode_arguments` - --> $WORKSPACE/precompiles/utils/src/solidity/codec/mod.rs - | - | pub fn encode_arguments(value: T) -> Vec { - | ^^^^^ required by this bound in `encode_arguments` diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.rs b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.rs deleted file mode 100644 index 278cffe68c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use fp_evm::PrecompileHandle; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(test: &mut impl PrecompileHandle) -> String { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.stderr deleted file mode 100644 index c104ae8fb3..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-not-result.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> tests/compile-fail/precompile/codec/output-not-result.rs:25:46 - | -25 | fn foo(test: &mut impl PrecompileHandle) -> String { - | ^^^^^^ the `?` operator cannot be applied to type `String` - | - = help: the trait `Try` is not implemented for `String` diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.rs b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.rs deleted file mode 100644 index d5d7c31a2c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use fp_evm::PrecompileHandle; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(test: &mut impl PrecompileHandle) -> Result<(), String> { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.stderr deleted file mode 100644 index fa1fc8f71c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/codec/output-wrong-error-result.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0277]: `?` couldn't convert the error to `PrecompileFailure` - --> tests/compile-fail/precompile/codec/output-wrong-error-result.rs:25:51 - | -25 | fn foo(test: &mut impl PrecompileHandle) -> Result<(), String> { - | ^ the trait `From` is not implemented for `PrecompileFailure` - | - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - > - > - > - > - = note: required for `Result` to implement `FromResidual>` diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.rs deleted file mode 100644 index 5c7d5fe26b..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::discriminant] - fn discriminant(address: H160) -> u32 { - 42 - } - - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.stderr deleted file mode 100644 index 66d90708f0..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/dont-return-option.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The discriminant function must return an Option<_> (no type alias) - --> tests/compile-fail/precompile/discriminant/dont-return-option.rs:25:36 - | -25 | fn discriminant(address: H160) -> u32 { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.rs deleted file mode 100644 index 0a27ed2bd4..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::public("foo()")] - fn foo(_discriminant: u32, handle: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.stderr deleted file mode 100644 index b24b8dddcb..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-fn.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: A PrecompileSet must have exactly one function tagged with `#[precompile::discriminant]` - --> tests/compile-fail/precompile/discriminant/missing-fn.rs:21:1 - | -21 | #[precompile_utils_macro::precompile] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `precompile_utils_macro::precompile` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.rs deleted file mode 100644 index 0447b2031a..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::discriminant] - fn discriminant() -> Option { - Some(42) - } - - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.stderr deleted file mode 100644 index 3026b5ce42..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/missing-param.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The discriminant function must only take the code address (H160) as parameter. - --> tests/compile-fail/precompile/discriminant/missing-param.rs:25:2 - | -25 | fn discriminant() -> Option { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.rs deleted file mode 100644 index 41f577bbc2..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::discriminant] - fn discriminant(address: H160) -> Option { - None - } - - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.stderr deleted file mode 100644 index dc6db9f600..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/return-incomplete-option.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The discriminant function must return an Option<_> (no type alias) - --> tests/compile-fail/precompile/discriminant/return-incomplete-option.rs:25:36 - | -25 | fn discriminant(address: H160) -> Option { - | ^^^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.rs deleted file mode 100644 index bbc2e1fe5f..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::discriminant] - fn discriminant(address: H160, other: u32) -> Option { - Some(42) - } - - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.stderr deleted file mode 100644 index a1b6e87865..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/too-many-arguments.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The discriminant function must only take the code address (H160) as parameter. - --> tests/compile-fail/precompile/discriminant/too-many-arguments.rs:25:2 - | -25 | fn discriminant(address: H160, other: u32) -> Option { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.rs deleted file mode 100644 index 620a0a98da..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::discriminant] - fn discriminant(address: H160) -> Option { - Some(42) - } - - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.stderr deleted file mode 100644 index 8d999769e4..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-1.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: All discriminants must have the same type (found u64 before) - --> tests/compile-fail/precompile/discriminant/type-mismatch-1.rs:30:24 - | -30 | fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.rs b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.rs deleted file mode 100644 index e0b2970863..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::public("foo()")] - fn foo(_discriminant: u32, test: &mut impl PrecompileHandle) -> EvmResult { - todo!() - } - - #[precompile::discriminant] - fn discriminant(address: H160) -> Option { - Some(42) - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.stderr deleted file mode 100644 index d5ed6750af..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/discriminant/type-mismatch-2.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: All discriminants must have the same type (found u32 before) - --> tests/compile-fail/precompile/discriminant/type-mismatch-2.rs:30:43 - | -30 | fn discriminant(address: H160) -> Option { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.rs b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.rs deleted file mode 100644 index ebe1bafcea..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.rs +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct PrecompileSet(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl PrecompileSet { - #[precompile::discriminant] - #[precompile::view] - fn foo(address: H160) -> Option { - None - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.stderr deleted file mode 100644 index 93f4fb2617..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The discriminant attribute must be the only precompile attribute of a function - --> tests/compile-fail/precompile/fn-modifiers/discriminant-multiple.rs:24:16 - | -24 | #[precompile::discriminant] - | ^^^^^^^^^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.rs b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.rs deleted file mode 100644 index 25db0a521c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.rs +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - #[precompile::view] - #[precompile::payable] - fn foo(_handle: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.stderr deleted file mode 100644 index 678199ab8b..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: A precompile method can have at most one modifier (payable, view) - --> tests/compile-fail/precompile/fn-modifiers/multiple-modifiers.rs:25:16 - | -25 | #[precompile::payable] - | ^^^^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.rs b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.rs deleted file mode 100644 index 31015637cc..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::pre_check] - #[precompile::view] - fn foo(handle: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.stderr deleted file mode 100644 index 7f96f8b568..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The pre_check attribute must be the only precompile attribute of a function - --> tests/compile-fail/precompile/fn-modifiers/pre-check-multiple.rs:23:16 - | -23 | #[precompile::pre_check] - | ^^^^^^^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.rs b/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.rs deleted file mode 100644 index 81770e7b5f..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo() { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.stderr deleted file mode 100644 index 2760a71988..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/missing.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Precompile methods must have at least 1 parameter (the PrecompileHandle) - --> tests/compile-fail/precompile/handle/missing.rs:24:2 - | -24 | fn foo() { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.rs b/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.rs deleted file mode 100644 index 8700c2742d..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::public("foo()")] - fn foo(_: u32) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.stderr deleted file mode 100644 index 8f0a10d8ff..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-missing.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: PrecompileSet methods must have at least 2 parameters (the precompile instance discriminant and the PrecompileHandle) - --> tests/compile-fail/precompile/handle/set-missing.rs:25:2 - | -25 | fn foo(_: u32) { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.rs b/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.rs deleted file mode 100644 index d571768bfa..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl Precompile { - #[precompile::public("foo()")] - fn foo(_discriminant: u32, _handle: u32) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.stderr deleted file mode 100644 index bf62c1381c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/set-wrong-type.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: This parameter must have type `&mut impl PrecompileHandle` - --> tests/compile-fail/precompile/handle/set-wrong-type.rs:25:38 - | -25 | fn foo(_discriminant: u32, _handle: u32) { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.rs b/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.rs deleted file mode 100644 index 01e1fb0f97..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::public("foo()")] - fn foo(_handle: u32) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.stderr deleted file mode 100644 index 12e06e4889..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/handle/wrong-type.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: This parameter must have type `&mut impl PrecompileHandle` - --> tests/compile-fail/precompile/handle/wrong-type.rs:24:18 - | -24 | fn foo(_handle: u32) { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.rs b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.rs deleted file mode 100644 index 7530add4dd..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::pre_check] - fn pre_check() { - todo!() - } - - #[precompile::public("foo()")] - fn foo(_handle: &mut impl PrecompileHandle) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.stderr deleted file mode 100644 index 406806c51c..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/no-parameter.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Precompile methods must have at least 1 parameter (the PrecompileHandle) - --> tests/compile-fail/precompile/pre-check/no-parameter.rs:24:2 - | -24 | fn pre_check() { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.rs b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.rs deleted file mode 100644 index 742c1d2c6f..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::pre_check] - fn pre_check(_: &mut impl PrecompileHandle, _: u32) { - todo!() - } - - #[precompile::public("foo()")] - fn foo(_handle: &mut impl PrecompileHandle) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.stderr deleted file mode 100644 index 474b5c9dcd..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/too-many-parameters.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Precompile pre_check method must have exactly 1 parameter (the PrecompileHandle) - --> tests/compile-fail/precompile/pre-check/too-many-parameters.rs:24:2 - | -24 | fn pre_check(_: &mut impl PrecompileHandle, _: u32) { - | ^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.rs b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.rs deleted file mode 100644 index 42b63886da..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl Precompile { - #[precompile::pre_check] - fn pre_check(_: u32) { - todo!() - } - - #[precompile::public("foo()")] - fn foo(_handle: &mut impl PrecompileHandle) { - todo!() - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.stderr deleted file mode 100644 index ea95fb0de8..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/pre-check/wrong-parameter.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: This parameter must have type `&mut impl PrecompileHandle` - --> tests/compile-fail/precompile/pre-check/wrong-parameter.rs:24:18 - | -24 | fn pre_check(_: u32) { - | ^^^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.rs b/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.rs deleted file mode 100644 index a5615e8fda..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; - -pub struct Precompile(PhantomData); - -#[precompile_utils_macro::precompile] -impl> Precompile { - #[precompile::public("foo(bytes)")] - fn foo(handle: &mut impl PrecompileHandle, arg: BoundedBytes) -> EvmResult { - Ok(()) - } -} - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.stderr b/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.stderr deleted file mode 100644 index 8b4daeb35f..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile/test-gen/generic-arg.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: impl type parameter is used in functions arguments. Arguments should not have a type - depending on a type parameter, unless it is a length bound for BoundedBytes, - BoundedString or alike, which doesn't affect the Solidity type. - - In that case, you must add a #[precompile::test_concrete_types(...)] attribute on the impl - block to provide concrete types that will be used to run the automatically generated tests - ensuring the Solidity function signatures are correct. - --> tests/compile-fail/precompile/test-gen/generic-arg.rs:24:63 - | -24 | fn foo(handle: &mut impl PrecompileHandle, arg: BoundedBytes) -> EvmResult { - | ^ diff --git a/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.rs b/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.rs deleted file mode 100644 index e328bfc092..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.rs +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -struct Dummy; - -#[precompile_utils_macro::precompile_name_from_address] -type Precompiles = Dummy; - -fn main() {} diff --git a/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.stderr b/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.stderr deleted file mode 100644 index 343443a248..0000000000 --- a/precompiles/utils/macro/tests/compile-fail/precompile_name/not_tuple.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Expected tuple - --> tests/compile-fail/precompile_name/not_tuple.rs:20:20 - | -20 | type Precompiles = Dummy; - | ^^^^^ diff --git a/precompiles/utils/macro/tests/expand/precompile.expanded.rs b/precompiles/utils/macro/tests/expand/precompile.expanded.rs deleted file mode 100644 index 3153ec9d06..0000000000 --- a/precompiles/utils/macro/tests/expand/precompile.expanded.rs +++ /dev/null @@ -1,364 +0,0 @@ -use core::marker::PhantomData; -use frame_support::pallet_prelude::{ConstU32, Get}; -use precompile_utils::{prelude::*, EvmResult}; -use sp_core::{H160, U256}; -struct BatchPrecompile(PhantomData); -type GetCallDataLimit = ConstU32<42>; -type GetArrayLimit = ConstU32<42>; -impl BatchPrecompile -where - Runtime: Get, -{ - fn pre_check(handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("pre_check") - )) - } - fn batch_some( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("batch_some") - )) - } - fn batch_some_until_failure( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("batch_some_until_failure") - )) - } - fn batch_all( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("batch_all") - )) - } - fn fallback(handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("fallback") - )) - } -} -#[allow(non_camel_case_types)] -pub enum BatchPrecompileCall -where - Runtime: Get, -{ - batch_all { - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - }, - batch_some { - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - }, - batch_some_until_failure { - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - }, - fallback {}, - #[doc(hidden)] - __phantom( - ::core::marker::PhantomData<(Runtime)>, - ::core::convert::Infallible, - ), -} -impl BatchPrecompileCall -where - Runtime: Get, -{ - pub fn parse_call_data( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::solidity::revert::RevertReason; - let input = handle.input(); - let selector = input.get(0..4).map(|s| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(s); - u32::from_be_bytes(buffer) - }); - match selector { - Some(2044677020u32) => Self::_parse_batch_some(handle), - Some(2531431096u32) => Self::_parse_batch_all(handle), - Some(3473183175u32) => Self::_parse_batch_some_until_failure(handle), - _ => Self::_parse_fallback(handle), - } - } - fn _parse_batch_all(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(4usize)?; - Ok(Self::batch_all { - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - call_data: input.read().in_field("callData")?, - gas_limit: input.read().in_field("gasLimit")?, - }) - } - fn _parse_batch_some( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(4usize)?; - Ok(Self::batch_some { - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - call_data: input.read().in_field("callData")?, - gas_limit: input.read().in_field("gasLimit")?, - }) - } - fn _parse_batch_some_until_failure( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(4usize)?; - Ok(Self::batch_some_until_failure { - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - call_data: input.read().in_field("callData")?, - gas_limit: input.read().in_field("gasLimit")?, - }) - } - fn _parse_fallback(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::fallback {}) - } - pub fn execute( - self, - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - use fp_evm::{ExitSucceed, PrecompileOutput}; - use precompile_utils::solidity::codec::Writer; - let output = match self { - Self::batch_all { - to, - value, - call_data, - gas_limit, - } => { - let output = - >::batch_all(handle, to, value, call_data, gas_limit); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::batch_some { - to, - value, - call_data, - gas_limit, - } => { - let output = - >::batch_some(handle, to, value, call_data, gas_limit); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::batch_some_until_failure { - to, - value, - call_data, - gas_limit, - } => { - let output = >::batch_some_until_failure( - handle, to, value, call_data, gas_limit, - ); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::fallback {} => { - let output = >::fallback(handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output, - }) - } - pub fn supports_selector(selector: u32) -> bool { - match selector { - 2044677020u32 => true, - 2531431096u32 => true, - 3473183175u32 => true, - _ => false, - } - } - pub fn selectors() -> &'static [u32] { - &[2044677020u32, 2531431096u32, 3473183175u32] - } - pub fn batch_all_selectors() -> &'static [u32] { - &[2531431096u32] - } - pub fn batch_some_selectors() -> &'static [u32] { - &[2044677020u32] - } - pub fn batch_some_until_failure_selectors() -> &'static [u32] { - &[3473183175u32] - } - pub fn fallback_selectors() -> &'static [u32] { - &[] - } - pub fn encode(self) -> ::sp_std::vec::Vec { - use precompile_utils::solidity::codec::Writer; - match self { - Self::batch_all { - to, - value, - call_data, - gas_limit, - } => Writer::new_with_selector(2531431096u32) - .write(to) - .write(value) - .write(call_data) - .write(gas_limit) - .build(), - Self::batch_some { - to, - value, - call_data, - gas_limit, - } => Writer::new_with_selector(2044677020u32) - .write(to) - .write(value) - .write(call_data) - .write(gas_limit) - .build(), - Self::batch_some_until_failure { - to, - value, - call_data, - gas_limit, - } => Writer::new_with_selector(3473183175u32) - .write(to) - .write(value) - .write(call_data) - .write(gas_limit) - .build(), - Self::fallback {} => Default::default(), - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - } - } -} -impl From> for ::sp_std::vec::Vec -where - Runtime: Get, -{ - fn from(a: BatchPrecompileCall) -> ::sp_std::vec::Vec { - a.encode() - } -} -impl ::fp_evm::Precompile for BatchPrecompile -where - Runtime: Get, -{ - fn execute( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - let _: () = >::pre_check(handle)?; - >::parse_call_data(handle)?.execute(handle) - } -} -#[allow(non_snake_case)] -pub(crate) fn __BatchPrecompile_test_solidity_signatures_inner() { - use precompile_utils::solidity::Codec; - match ( - &"(address[],uint256[],bytes[],uint64[])", - &<( - BoundedVec, - BoundedVec, - BoundedVec, GetArrayLimit>, - BoundedVec, - ) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "batch_all" ), ), ); - } - } - }; - match ( - &"(address[],uint256[],bytes[],uint64[])", - &<( - BoundedVec, - BoundedVec, - BoundedVec, GetArrayLimit>, - BoundedVec, - ) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "batch_some" ), ), ); - } - } - }; - match ( - &"(address[],uint256[],bytes[],uint64[])", - &<( - BoundedVec, - BoundedVec, - BoundedVec, GetArrayLimit>, - BoundedVec, - ) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "batch_some_until_failure" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "fallback" ), ), ); - } - } - }; -} diff --git a/precompiles/utils/macro/tests/expand/precompile.rs b/precompiles/utils/macro/tests/expand/precompile.rs deleted file mode 100644 index 6cb99baed6..0000000000 --- a/precompiles/utils/macro/tests/expand/precompile.rs +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use frame_support::pallet_prelude::{ConstU32, Get}; -use precompile_utils::{prelude::*, EvmResult}; -use sp_core::{H160, U256}; - -// Based on Batch with stripped code. - -struct BatchPrecompile(PhantomData); - -type GetCallDataLimit = ConstU32<42>; -type GetArrayLimit = ConstU32<42>; - -#[precompile_utils_macro::precompile] -impl BatchPrecompile -where - Runtime: Get, -{ - #[precompile::pre_check] - fn pre_check(handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("pre_check") - } - - #[precompile::public("batchSome(address[],uint256[],bytes[],uint64[])")] - fn batch_some( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - todo!("batch_some") - } - - #[precompile::public("batchSomeUntilFailure(address[],uint256[],bytes[],uint64[])")] - fn batch_some_until_failure( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - todo!("batch_some_until_failure") - } - - #[precompile::public("batchAll(address[],uint256[],bytes[],uint64[])")] - fn batch_all( - handle: &mut impl PrecompileHandle, - to: BoundedVec, - value: BoundedVec, - call_data: BoundedVec, GetArrayLimit>, - gas_limit: BoundedVec, - ) -> EvmResult { - todo!("batch_all") - } - - // additional function to check fallback - #[precompile::fallback] - fn fallback(handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("fallback") - } -} diff --git a/precompiles/utils/macro/tests/expand/precompile_name.expanded.rs b/precompiles/utils/macro/tests/expand/precompile_name.expanded.rs deleted file mode 100644 index ebe51ecade..0000000000 --- a/precompiles/utils/macro/tests/expand/precompile_name.expanded.rs +++ /dev/null @@ -1,37 +0,0 @@ -struct PrecompileAt(PhantomData<(T, U, V)>); -struct AddressU64; -struct FooPrecompile(PhantomData); -struct BarPrecompile(PhantomData<(R, S)>); -struct MockCheck; -type Precompiles = ( - PrecompileAt, FooPrecompile>, - PrecompileAt, BarPrecompile, (MockCheck, MockCheck)>, -); -#[repr(u64)] -pub enum PrecompileName { - FooPrecompile = 1u64, - BarPrecompile = 2u64, -} -#[automatically_derived] -impl ::core::fmt::Debug for PrecompileName { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::write_str( - f, - match self { - PrecompileName::FooPrecompile => "FooPrecompile", - PrecompileName::BarPrecompile => "BarPrecompile", - }, - ) - } -} -impl PrecompileName { - pub fn from_address(address: sp_core::H160) -> Option { - let _u64 = address.to_low_u64_be(); - if address == sp_core::H160::from_low_u64_be(_u64) { - use num_enum::TryFromPrimitive; - Self::try_from_primitive(_u64).ok() - } else { - None - } - } -} diff --git a/precompiles/utils/macro/tests/expand/precompile_name.rs b/precompiles/utils/macro/tests/expand/precompile_name.rs deleted file mode 100644 index 5c6a6cb11d..0000000000 --- a/precompiles/utils/macro/tests/expand/precompile_name.rs +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// Few mock structs to check the macro. -struct PrecompileAt(PhantomData<(T, U, V)>); -struct AddressU64; -struct FooPrecompile(PhantomData); -struct BarPrecompile(PhantomData<(R, S)>); -struct MockCheck; - -#[precompile_utils_macro::precompile_name_from_address] -type Precompiles = ( - PrecompileAt, FooPrecompile>, - PrecompileAt, BarPrecompile, (MockCheck, MockCheck)>, -); diff --git a/precompiles/utils/macro/tests/expand/precompileset.expanded.rs b/precompiles/utils/macro/tests/expand/precompileset.expanded.rs deleted file mode 100644 index d3750bb6bc..0000000000 --- a/precompiles/utils/macro/tests/expand/precompileset.expanded.rs +++ /dev/null @@ -1,1257 +0,0 @@ -use core::marker::PhantomData; -use precompile_utils::{prelude::*, testing::PrecompileTesterExt, EvmResult}; -use sp_core::H160; -struct PrecompileSet(PhantomData); -type Discriminant = u32; -type GetAssetsStringLimit = R; -type MockRuntime = ConstU32<42>; -impl PrecompileSet -where - Runtime: Get, -{ - /// PrecompileSet discrimiant. Allows to knows if the address maps to an asset id, - /// and if this is the case which one. - fn discriminant(address: H160) -> Option { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("discriminant") - )) - } - fn total_supply(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("total_supply") - )) - } - fn balance_of( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - who: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("balance_of") - )) - } - fn allowance( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - spender: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("allowance") - )) - } - fn approve( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - spender: Address, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("approve") - )) - } - fn approve_inner( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: H160, - spender: H160, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("approve_inner") - )) - } - fn transfer( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - to: Address, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("transfer") - )) - } - fn transfer_from( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - from: Address, - to: Address, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("transfer_from") - )) - } - fn name( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("name") - )) - } - fn symbol( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("symbol") - )) - } - fn decimals(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("decimals") - )) - } - fn mint( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - to: Address, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("mint") - )) - } - fn burn( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - from: Address, - value: U256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("burn") - )) - } - fn freeze( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - account: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("freeze") - )) - } - fn thaw( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - account: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("thaw") - )) - } - fn freeze_asset(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("freeze_asset") - )) - } - fn thaw_asset(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("thaw_asset") - )) - } - fn transfer_ownership( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("transfer_ownership") - )) - } - fn set_team( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - issuer: Address, - admin: Address, - freezer: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("set_team") - )) - } - fn set_metadata( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - name: BoundedString>, - symbol: BoundedString>, - decimals: u8, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("set_metadata") - )) - } - fn clear_metadata( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("clear_metadata") - )) - } - fn eip2612_permit( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - spender: Address, - value: U256, - deadline: U256, - v: u8, - r: H256, - s: H256, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("eip2612_permit") - )) - } - fn eip2612_nonces( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("eip2612_nonces") - )) - } - fn eip2612_domain_separator( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("eip2612_domain_separator") - )) - } -} -#[allow(non_camel_case_types)] -pub enum PrecompileSetCall -where - Runtime: Get, -{ - allowance { - owner: Address, - spender: Address, - }, - approve { - spender: Address, - value: U256, - }, - balance_of { - who: Address, - }, - burn { - from: Address, - value: U256, - }, - clear_metadata {}, - decimals {}, - eip2612_domain_separator {}, - eip2612_nonces { - owner: Address, - }, - eip2612_permit { - owner: Address, - spender: Address, - value: U256, - deadline: U256, - v: u8, - r: H256, - s: H256, - }, - freeze { - account: Address, - }, - freeze_asset {}, - mint { - to: Address, - value: U256, - }, - name {}, - set_metadata { - name: BoundedString>, - symbol: BoundedString>, - decimals: u8, - }, - set_team { - issuer: Address, - admin: Address, - freezer: Address, - }, - symbol {}, - thaw { - account: Address, - }, - thaw_asset {}, - total_supply {}, - transfer { - to: Address, - value: U256, - }, - transfer_from { - from: Address, - to: Address, - value: U256, - }, - transfer_ownership { - owner: Address, - }, - #[doc(hidden)] - __phantom( - ::core::marker::PhantomData<(Runtime)>, - ::core::convert::Infallible, - ), -} -impl PrecompileSetCall -where - Runtime: Get, -{ - pub fn parse_call_data( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::solidity::revert::RevertReason; - let input = handle.input(); - let selector = input.get(0..4).map(|s| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(s); - u32::from_be_bytes(buffer) - }); - match selector { - Some(117300739u32) => Self::_parse_name(handle), - Some(157198259u32) => Self::_parse_approve(handle), - Some(404098525u32) => Self::_parse_total_supply(handle), - Some(484305945u32) => Self::_parse_thaw_asset(handle), - Some(599290589u32) => Self::_parse_transfer_from(handle), - Some(826074471u32) => Self::_parse_decimals(handle), - Some(910484757u32) => Self::_parse_eip2612_domain_separator(handle), - Some(936559348u32) => Self::_parse_set_metadata(handle), - Some(1086394137u32) => Self::_parse_mint(handle), - Some(1374431959u32) => Self::_parse_thaw_asset(handle), - Some(1587675670u32) => Self::_parse_thaw(handle), - Some(1804030401u32) => Self::_parse_freeze_asset(handle), - Some(1889567281u32) => Self::_parse_balance_of(handle), - Some(2127478272u32) => Self::_parse_eip2612_nonces(handle), - Some(2367676207u32) => Self::_parse_freeze(handle), - Some(2514000705u32) => Self::_parse_symbol(handle), - Some(2646777772u32) => Self::_parse_burn(handle), - Some(2835717307u32) => Self::_parse_transfer(handle), - Some(3352902745u32) => Self::_parse_set_team(handle), - Some(3552201630u32) => Self::_parse_clear_metadata(handle), - Some(3566436177u32) => Self::_parse_freeze_asset(handle), - Some(3573918927u32) => Self::_parse_eip2612_permit(handle), - Some(3714247998u32) => Self::_parse_allowance(handle), - Some(3999121892u32) => Self::_parse_set_metadata(handle), - Some(4021736498u32) => Self::_parse_clear_metadata(handle), - Some(4030008324u32) => Self::_parse_transfer_ownership(handle), - Some(4076725131u32) => Self::_parse_transfer_ownership(handle), - Some(4173303445u32) => Self::_parse_set_team(handle), - Some(_) => Err(RevertReason::UnknownSelector.into()), - None => Err(RevertReason::read_out_of_bounds("selector").into()), - } - } - fn _parse_allowance(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(2usize)?; - Ok(Self::allowance { - owner: input.read().in_field("owner")?, - spender: input.read().in_field("spender")?, - }) - } - fn _parse_approve(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(2usize)?; - Ok(Self::approve { - spender: input.read().in_field("spender")?, - value: input.read().in_field("value")?, - }) - } - fn _parse_balance_of( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(1usize)?; - Ok(Self::balance_of { - who: input.read().in_field("who")?, - }) - } - fn _parse_burn(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(2usize)?; - Ok(Self::burn { - from: input.read().in_field("from")?, - value: input.read().in_field("value")?, - }) - } - fn _parse_clear_metadata( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::clear_metadata {}) - } - fn _parse_decimals(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::decimals {}) - } - fn _parse_eip2612_domain_separator( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::View)?; - Ok(Self::eip2612_domain_separator {}) - } - fn _parse_eip2612_nonces( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::View)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(1usize)?; - Ok(Self::eip2612_nonces { - owner: input.read().in_field("owner")?, - }) - } - fn _parse_eip2612_permit( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(7usize)?; - Ok(Self::eip2612_permit { - owner: input.read().in_field("owner")?, - spender: input.read().in_field("spender")?, - value: input.read().in_field("value")?, - deadline: input.read().in_field("deadline")?, - v: input.read().in_field("v")?, - r: input.read().in_field("r")?, - s: input.read().in_field("s")?, - }) - } - fn _parse_freeze(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(1usize)?; - Ok(Self::freeze { - account: input.read().in_field("account")?, - }) - } - fn _parse_freeze_asset( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::freeze_asset {}) - } - fn _parse_mint(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(2usize)?; - Ok(Self::mint { - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - }) - } - fn _parse_name(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::name {}) - } - fn _parse_set_metadata( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(3usize)?; - Ok(Self::set_metadata { - name: input.read().in_field("name")?, - symbol: input.read().in_field("symbol")?, - decimals: input.read().in_field("decimals")?, - }) - } - fn _parse_set_team(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(3usize)?; - Ok(Self::set_team { - issuer: input.read().in_field("issuer")?, - admin: input.read().in_field("admin")?, - freezer: input.read().in_field("freezer")?, - }) - } - fn _parse_symbol(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::symbol {}) - } - fn _parse_thaw(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(1usize)?; - Ok(Self::thaw { - account: input.read().in_field("account")?, - }) - } - fn _parse_thaw_asset( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::thaw_asset {}) - } - fn _parse_total_supply( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::total_supply {}) - } - fn _parse_transfer(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(2usize)?; - Ok(Self::transfer { - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - }) - } - fn _parse_transfer_from( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(3usize)?; - Ok(Self::transfer_from { - from: input.read().in_field("from")?, - to: input.read().in_field("to")?, - value: input.read().in_field("value")?, - }) - } - fn _parse_transfer_ownership( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - let mut input = handle.read_after_selector()?; - input.expect_arguments(1usize)?; - Ok(Self::transfer_ownership { - owner: input.read().in_field("owner")?, - }) - } - pub fn execute( - self, - discriminant: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - use fp_evm::{ExitSucceed, PrecompileOutput}; - use precompile_utils::solidity::codec::Writer; - let output = match self { - Self::allowance { owner, spender } => { - let output = - >::allowance(discriminant, handle, owner, spender); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::approve { spender, value } => { - let output = - >::approve(discriminant, handle, spender, value); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::balance_of { who } => { - let output = >::balance_of(discriminant, handle, who); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::burn { from, value } => { - let output = >::burn(discriminant, handle, from, value); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::clear_metadata {} => { - let output = >::clear_metadata(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::decimals {} => { - let output = >::decimals(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::eip2612_domain_separator {} => { - let output = - >::eip2612_domain_separator(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::eip2612_nonces { owner } => { - let output = >::eip2612_nonces(discriminant, handle, owner); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::eip2612_permit { - owner, - spender, - value, - deadline, - v, - r, - s, - } => { - let output = >::eip2612_permit( - discriminant, - handle, - owner, - spender, - value, - deadline, - v, - r, - s, - ); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::freeze { account } => { - let output = >::freeze(discriminant, handle, account); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::freeze_asset {} => { - let output = >::freeze_asset(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::mint { to, value } => { - let output = >::mint(discriminant, handle, to, value); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::name {} => { - let output = >::name(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::set_metadata { - name, - symbol, - decimals, - } => { - let output = >::set_metadata( - discriminant, - handle, - name, - symbol, - decimals, - ); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::set_team { - issuer, - admin, - freezer, - } => { - let output = >::set_team( - discriminant, - handle, - issuer, - admin, - freezer, - ); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::symbol {} => { - let output = >::symbol(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::thaw { account } => { - let output = >::thaw(discriminant, handle, account); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::thaw_asset {} => { - let output = >::thaw_asset(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::total_supply {} => { - let output = >::total_supply(discriminant, handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::transfer { to, value } => { - let output = >::transfer(discriminant, handle, to, value); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::transfer_from { from, to, value } => { - let output = - >::transfer_from(discriminant, handle, from, to, value); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::transfer_ownership { owner } => { - let output = - >::transfer_ownership(discriminant, handle, owner); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output, - }) - } - pub fn supports_selector(selector: u32) -> bool { - match selector { - 117300739u32 => true, - 157198259u32 => true, - 404098525u32 => true, - 484305945u32 => true, - 599290589u32 => true, - 826074471u32 => true, - 910484757u32 => true, - 936559348u32 => true, - 1086394137u32 => true, - 1374431959u32 => true, - 1587675670u32 => true, - 1804030401u32 => true, - 1889567281u32 => true, - 2127478272u32 => true, - 2367676207u32 => true, - 2514000705u32 => true, - 2646777772u32 => true, - 2835717307u32 => true, - 3352902745u32 => true, - 3552201630u32 => true, - 3566436177u32 => true, - 3573918927u32 => true, - 3714247998u32 => true, - 3999121892u32 => true, - 4021736498u32 => true, - 4030008324u32 => true, - 4076725131u32 => true, - 4173303445u32 => true, - _ => false, - } - } - pub fn selectors() -> &'static [u32] { - &[ - 117300739u32, - 157198259u32, - 404098525u32, - 484305945u32, - 599290589u32, - 826074471u32, - 910484757u32, - 936559348u32, - 1086394137u32, - 1374431959u32, - 1587675670u32, - 1804030401u32, - 1889567281u32, - 2127478272u32, - 2367676207u32, - 2514000705u32, - 2646777772u32, - 2835717307u32, - 3352902745u32, - 3552201630u32, - 3566436177u32, - 3573918927u32, - 3714247998u32, - 3999121892u32, - 4021736498u32, - 4030008324u32, - 4076725131u32, - 4173303445u32, - ] - } - pub fn allowance_selectors() -> &'static [u32] { - &[3714247998u32] - } - pub fn approve_selectors() -> &'static [u32] { - &[157198259u32] - } - pub fn balance_of_selectors() -> &'static [u32] { - &[1889567281u32] - } - pub fn burn_selectors() -> &'static [u32] { - &[2646777772u32] - } - pub fn clear_metadata_selectors() -> &'static [u32] { - &[4021736498u32, 3552201630u32] - } - pub fn decimals_selectors() -> &'static [u32] { - &[826074471u32] - } - pub fn eip2612_domain_separator_selectors() -> &'static [u32] { - &[910484757u32] - } - pub fn eip2612_nonces_selectors() -> &'static [u32] { - &[2127478272u32] - } - pub fn eip2612_permit_selectors() -> &'static [u32] { - &[3573918927u32] - } - pub fn freeze_selectors() -> &'static [u32] { - &[2367676207u32] - } - pub fn freeze_asset_selectors() -> &'static [u32] { - &[3566436177u32, 1804030401u32] - } - pub fn mint_selectors() -> &'static [u32] { - &[1086394137u32] - } - pub fn name_selectors() -> &'static [u32] { - &[117300739u32] - } - pub fn set_metadata_selectors() -> &'static [u32] { - &[936559348u32, 3999121892u32] - } - pub fn set_team_selectors() -> &'static [u32] { - &[3352902745u32, 4173303445u32] - } - pub fn symbol_selectors() -> &'static [u32] { - &[2514000705u32] - } - pub fn thaw_selectors() -> &'static [u32] { - &[1587675670u32] - } - pub fn thaw_asset_selectors() -> &'static [u32] { - &[1374431959u32, 484305945u32] - } - pub fn total_supply_selectors() -> &'static [u32] { - &[404098525u32] - } - pub fn transfer_selectors() -> &'static [u32] { - &[2835717307u32] - } - pub fn transfer_from_selectors() -> &'static [u32] { - &[599290589u32] - } - pub fn transfer_ownership_selectors() -> &'static [u32] { - &[4076725131u32, 4030008324u32] - } - pub fn encode(self) -> ::sp_std::vec::Vec { - use precompile_utils::solidity::codec::Writer; - match self { - Self::allowance { owner, spender } => Writer::new_with_selector(3714247998u32) - .write(owner) - .write(spender) - .build(), - Self::approve { spender, value } => Writer::new_with_selector(157198259u32) - .write(spender) - .write(value) - .build(), - Self::balance_of { who } => Writer::new_with_selector(1889567281u32).write(who).build(), - Self::burn { from, value } => Writer::new_with_selector(2646777772u32) - .write(from) - .write(value) - .build(), - Self::clear_metadata {} => Writer::new_with_selector(4021736498u32).build(), - Self::decimals {} => Writer::new_with_selector(826074471u32).build(), - Self::eip2612_domain_separator {} => Writer::new_with_selector(910484757u32).build(), - Self::eip2612_nonces { owner } => Writer::new_with_selector(2127478272u32) - .write(owner) - .build(), - Self::eip2612_permit { - owner, - spender, - value, - deadline, - v, - r, - s, - } => Writer::new_with_selector(3573918927u32) - .write(owner) - .write(spender) - .write(value) - .write(deadline) - .write(v) - .write(r) - .write(s) - .build(), - Self::freeze { account } => Writer::new_with_selector(2367676207u32) - .write(account) - .build(), - Self::freeze_asset {} => Writer::new_with_selector(3566436177u32).build(), - Self::mint { to, value } => Writer::new_with_selector(1086394137u32) - .write(to) - .write(value) - .build(), - Self::name {} => Writer::new_with_selector(117300739u32).build(), - Self::set_metadata { - name, - symbol, - decimals, - } => Writer::new_with_selector(936559348u32) - .write(name) - .write(symbol) - .write(decimals) - .build(), - Self::set_team { - issuer, - admin, - freezer, - } => Writer::new_with_selector(3352902745u32) - .write(issuer) - .write(admin) - .write(freezer) - .build(), - Self::symbol {} => Writer::new_with_selector(2514000705u32).build(), - Self::thaw { account } => Writer::new_with_selector(1587675670u32) - .write(account) - .build(), - Self::thaw_asset {} => Writer::new_with_selector(1374431959u32).build(), - Self::total_supply {} => Writer::new_with_selector(404098525u32).build(), - Self::transfer { to, value } => Writer::new_with_selector(2835717307u32) - .write(to) - .write(value) - .build(), - Self::transfer_from { from, to, value } => Writer::new_with_selector(599290589u32) - .write(from) - .write(to) - .write(value) - .build(), - Self::transfer_ownership { owner } => Writer::new_with_selector(4076725131u32) - .write(owner) - .build(), - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - } - } -} -impl From> for ::sp_std::vec::Vec -where - Runtime: Get, -{ - fn from(a: PrecompileSetCall) -> ::sp_std::vec::Vec { - a.encode() - } -} -impl ::fp_evm::PrecompileSet for PrecompileSet -where - Runtime: Get, -{ - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option<::precompile_utils::EvmResult<::fp_evm::PrecompileOutput>> { - let discriminant = match >::discriminant(handle.code_address()) { - Some(d) => d, - None => return None, - }; - Some( - >::parse_call_data(handle) - .and_then(|call| call.execute(discriminant, handle)), - ) - } - fn is_precompile(&self, address: H160, gas: u64) -> ::fp_evm::IsPrecompileResult { - >::discriminant(address, gas).is_some() - } -} -#[allow(non_snake_case)] -pub(crate) fn __PrecompileSet_test_solidity_signatures_inner() -where - Runtime: Get, -{ - use precompile_utils::solidity::Codec; - match ( - &"(address,address)", - &<(Address, Address) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "allowance" ), ), ); - } - } - }; - match ( - &"(address,uint256)", - &<(Address, U256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "approve" ), ), ); - } - } - }; - match (&"(address)", &<(Address,) as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "balance_of" ), ), ); - } - } - }; - match ( - &"(address,uint256)", - &<(Address, U256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "burn" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "clear_metadata" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "decimals" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "eip2612_domain_separator" ), ), ); - } - } - }; - match (&"(address)", &<(Address,) as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "eip2612_nonces" ), ), ); - } - } - }; - match ( - &"(address,address,uint256,uint256,uint8,bytes32,bytes32)", - &<(Address, Address, U256, U256, u8, H256, H256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "eip2612_permit" ), ), ); - } - } - }; - match (&"(address)", &<(Address,) as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "freeze" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "freeze_asset" ), ), ); - } - } - }; - match ( - &"(address,uint256)", - &<(Address, U256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "mint" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "name" ), ), ); - } - } - }; - match ( - &"(string,string,uint8)", - &<( - BoundedString>, - BoundedString>, - u8, - ) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "set_metadata" ), ), ); - } - } - }; - match ( - &"(address,address,address)", - &<(Address, Address, Address) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "set_team" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "symbol" ), ), ); - } - } - }; - match (&"(address)", &<(Address,) as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "thaw" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "thaw_asset" ), ), ); - } - } - }; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "total_supply" ), ), ); - } - } - }; - match ( - &"(address,uint256)", - &<(Address, U256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "transfer" ), ), ); - } - } - }; - match ( - &"(address,address,uint256)", - &<(Address, Address, U256) as Codec>::signature(), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "transfer_from" ), ), ); - } - } - }; - match (&"(address)", &<(Address,) as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "transfer_ownership" ), ), ); - } - } - }; -} diff --git a/precompiles/utils/macro/tests/expand/precompileset.rs b/precompiles/utils/macro/tests/expand/precompileset.rs deleted file mode 100644 index d9fa8e91b9..0000000000 --- a/precompiles/utils/macro/tests/expand/precompileset.rs +++ /dev/null @@ -1,259 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use core::marker::PhantomData; -use precompile_utils::{prelude::*, testing::PrecompileTesterExt, EvmResult}; -use sp_core::H160; - -// Based on Erc20AssetsPrecompileSet with stripped code. - -struct PrecompileSet(PhantomData); - -type Discriminant = u32; -type GetAssetsStringLimit = R; -type MockRuntime = ConstU32<42>; - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -#[precompile::test_concrete_types(MockRuntime)] -impl PrecompileSet -where - Runtime: Get, -{ - /// PrecompileSet discrimiant. Allows to knows if the address maps to an asset id, - /// and if this is the case which one. - #[precompile::discriminant] - fn discriminant(address: H160) -> Option { - todo!("discriminant") - } - - #[precompile::public("totalSupply()")] - fn total_supply(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("total_supply") - } - - #[precompile::public("balanceOf(address)")] - fn balance_of( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - who: Address, - ) -> EvmResult { - todo!("balance_of") - } - - #[precompile::public("allowance(address,address)")] - fn allowance( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - spender: Address, - ) -> EvmResult { - todo!("allowance") - } - - #[precompile::public("approve(address,uint256)")] - fn approve( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - spender: Address, - value: U256, - ) -> EvmResult { - todo!("approve") - } - - fn approve_inner( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: H160, - spender: H160, - value: U256, - ) -> EvmResult { - todo!("approve_inner") - } - - #[precompile::public("transfer(address,uint256)")] - fn transfer( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - to: Address, - value: U256, - ) -> EvmResult { - todo!("transfer") - } - - #[precompile::public("transferFrom(address,address,uint256)")] - fn transfer_from( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - from: Address, - to: Address, - value: U256, - ) -> EvmResult { - todo!("transfer_from") - } - - #[precompile::public("name()")] - fn name( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - todo!("name") - } - - #[precompile::public("symbol()")] - fn symbol( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - todo!("symbol") - } - - #[precompile::public("decimals()")] - fn decimals(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("decimals") - } - - // From here: only for locals, we need to check whether we are in local assets otherwise fail - #[precompile::public("mint(address,uint256)")] - fn mint( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - to: Address, - value: U256, - ) -> EvmResult { - todo!("mint") - } - - #[precompile::public("burn(address,uint256)")] - fn burn( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - from: Address, - value: U256, - ) -> EvmResult { - todo!("burn") - } - - #[precompile::public("freeze(address)")] - fn freeze( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - account: Address, - ) -> EvmResult { - todo!("freeze") - } - - #[precompile::public("thaw(address)")] - fn thaw( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - account: Address, - ) -> EvmResult { - todo!("thaw") - } - - #[precompile::public("freezeAsset()")] - #[precompile::public("freeze_asset()")] - fn freeze_asset(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("freeze_asset") - } - - #[precompile::public("thawAsset()")] - #[precompile::public("thaw_asset()")] - fn thaw_asset(asset_id: Discriminant, handle: &mut impl PrecompileHandle) -> EvmResult { - todo!("thaw_asset") - } - - #[precompile::public("transferOwnership(address)")] - #[precompile::public("transfer_ownership(address)")] - fn transfer_ownership( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - ) -> EvmResult { - todo!("transfer_ownership") - } - - #[precompile::public("setTeam(address,address,address)")] - #[precompile::public("set_team(address,address,address)")] - fn set_team( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - issuer: Address, - admin: Address, - freezer: Address, - ) -> EvmResult { - todo!("set_team") - } - - #[precompile::public("setMetadata(string,string,uint8)")] - #[precompile::public("set_metadata(string,string,uint8)")] - fn set_metadata( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - name: BoundedString>, - symbol: BoundedString>, - decimals: u8, - ) -> EvmResult { - todo!("set_metadata") - } - - #[precompile::public("clearMetadata()")] - #[precompile::public("clear_metadata()")] - fn clear_metadata( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - todo!("clear_metadata") - } - - #[precompile::public("permit(address,address,uint256,uint256,uint8,bytes32,bytes32)")] - fn eip2612_permit( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - spender: Address, - value: U256, - deadline: U256, - v: u8, - r: H256, - s: H256, - ) -> EvmResult { - todo!("eip2612_permit") - } - - #[precompile::public("nonces(address)")] - #[precompile::view] - fn eip2612_nonces( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - owner: Address, - ) -> EvmResult { - todo!("eip2612_nonces") - } - - #[precompile::public("DOMAIN_SEPARATOR()")] - #[precompile::view] - fn eip2612_domain_separator( - asset_id: Discriminant, - handle: &mut impl PrecompileHandle, - ) -> EvmResult { - todo!("eip2612_domain_separator") - } -} diff --git a/precompiles/utils/macro/tests/expand/returns_tuple.expanded.rs b/precompiles/utils/macro/tests/expand/returns_tuple.expanded.rs deleted file mode 100644 index 6d11310310..0000000000 --- a/precompiles/utils/macro/tests/expand/returns_tuple.expanded.rs +++ /dev/null @@ -1,108 +0,0 @@ -use precompile_utils::{prelude::*, EvmResult}; -use sp_core::{H160, U256}; -struct ExamplePrecompile; -impl ExamplePrecompile { - fn example(handle: &mut impl PrecompileHandle) -> EvmResult<(Address, U256, UnboundedBytes)> { - ::core::panicking::panic_fmt(format_args!( - "not yet implemented: {0}", - format_args!("example") - )) - } -} -#[allow(non_camel_case_types)] -pub enum ExamplePrecompileCall { - example {}, - #[doc(hidden)] - __phantom(::core::marker::PhantomData<()>, ::core::convert::Infallible), -} -impl ExamplePrecompileCall { - pub fn parse_call_data( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult { - use precompile_utils::solidity::revert::RevertReason; - let input = handle.input(); - let selector = input.get(0..4).map(|s| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(s); - u32::from_be_bytes(buffer) - }); - match selector { - Some(1412775727u32) => Self::_parse_example(handle), - Some(_) => Err(RevertReason::UnknownSelector.into()), - None => Err(RevertReason::read_out_of_bounds("selector").into()), - } - } - fn _parse_example(handle: &mut impl PrecompileHandle) -> ::precompile_utils::EvmResult { - use precompile_utils::{ - evm::handle::PrecompileHandleExt, - solidity::{modifier::FunctionModifier, revert::InjectBacktrace}, - }; - handle.check_function_modifier(FunctionModifier::NonPayable)?; - Ok(Self::example {}) - } - pub fn execute( - self, - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - use fp_evm::{ExitSucceed, PrecompileOutput}; - use precompile_utils::solidity::codec::Writer; - let output = match self { - Self::example {} => { - let output = ::example(handle); - ::precompile_utils::solidity::encode_return_value(output?) - } - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output, - }) - } - pub fn supports_selector(selector: u32) -> bool { - match selector { - 1412775727u32 => true, - _ => false, - } - } - pub fn selectors() -> &'static [u32] { - &[1412775727u32] - } - pub fn example_selectors() -> &'static [u32] { - &[1412775727u32] - } - pub fn encode(self) -> ::sp_std::vec::Vec { - use precompile_utils::solidity::codec::Writer; - match self { - Self::example {} => Writer::new_with_selector(1412775727u32).build(), - Self::__phantom(_, _) => { - ::core::panicking::panic_fmt(format_args!("__phantom variant should not be used")) - } - } - } -} -impl From for ::sp_std::vec::Vec { - fn from(a: ExamplePrecompileCall) -> ::sp_std::vec::Vec { - a.encode() - } -} -impl ::fp_evm::Precompile for ExamplePrecompile { - fn execute( - handle: &mut impl PrecompileHandle, - ) -> ::precompile_utils::EvmResult<::fp_evm::PrecompileOutput> { - ::parse_call_data(handle)?.execute(handle) - } -} -#[allow(non_snake_case)] -pub(crate) fn __ExamplePrecompile_test_solidity_signatures_inner() { - use precompile_utils::solidity::Codec; - match (&"()", &<() as Codec>::signature()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( kind, &*left_val, &*right_val, ::core::option::Option::Some( format_args!( "{0} function signature doesn\'t match (left: attribute, right: computed from Rust types)", "example" ), ), ); - } - } - }; -} diff --git a/precompiles/utils/macro/tests/expand/returns_tuple.rs b/precompiles/utils/macro/tests/expand/returns_tuple.rs deleted file mode 100644 index 8fa5b160db..0000000000 --- a/precompiles/utils/macro/tests/expand/returns_tuple.rs +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use precompile_utils::{prelude::*, EvmResult}; -use sp_core::{H160, U256}; - -struct ExamplePrecompile; - -#[precompile_utils_macro::precompile] -impl ExamplePrecompile { - #[precompile::public("example()")] - fn example(handle: &mut impl PrecompileHandle) -> EvmResult<(Address, U256, UnboundedBytes)> { - todo!("example") - } -} diff --git a/precompiles/utils/macro/tests/pass/derive_codec.rs b/precompiles/utils/macro/tests/pass/derive_codec.rs deleted file mode 100644 index 8d63c2bdce..0000000000 --- a/precompiles/utils/macro/tests/pass/derive_codec.rs +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use precompile_utils::solidity::codec::{Address, Codec, Reader, Writer}; -use sp_core::H160; - -#[derive(Debug, Clone, PartialEq, Eq, Codec)] -struct StaticSize { - id: u32, - address: Address, -} - -#[derive(Debug, Clone, PartialEq, Eq, Codec)] -struct DynamicSize { - id: u32, - array: Vec, -} - -fn main() { - // static - let static_size = StaticSize { - id: 5, - address: H160::repeat_byte(0x42).into(), - }; - - assert!(StaticSize::has_static_size()); - assert_eq!(&StaticSize::signature(), "(uint32,address)"); - - let bytes = Writer::new().write(static_size.clone()).build(); - assert_eq!( - bytes, - Writer::new() - .write(5u32) - .write(Address::from(H160::repeat_byte(0x42))) - .build() - ); - - let mut reader = Reader::new(&bytes); - let static_size_2: StaticSize = reader.read().expect("to decode properly"); - assert_eq!(static_size_2, static_size); - - // dynamic - let dynamic_size = DynamicSize { - id: 6, - array: vec![10u32, 15u32], - }; - assert!(!DynamicSize::::has_static_size()); - assert_eq!(DynamicSize::::signature(), "(uint32,uint32[])"); - - let bytes = Writer::new().write(dynamic_size.clone()).build(); - assert_eq!( - bytes, - Writer::new() - .write(0x20u32) // offset of struct - .write(6u32) // id - .write(0x40u32) // array offset - .write(2u32) // array size - .write(10u32) // array[0] - .write(15u32) // array[1] - .build() - ); - - let mut reader = Reader::new(&bytes); - let dynamic_size_2: DynamicSize = reader.read().expect("to decode properly"); - assert_eq!(dynamic_size_2, dynamic_size); -} diff --git a/precompiles/utils/macro/tests/pass/precompile_fn_modifiers.rs b/precompiles/utils/macro/tests/pass/precompile_fn_modifiers.rs deleted file mode 100644 index 97a514766a..0000000000 --- a/precompiles/utils/macro/tests/pass/precompile_fn_modifiers.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright PureStake Inc. -// This file is part of Moonbeam. - -// Moonbeam is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Moonbeam is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -use precompile_utils::{prelude::*, testing::PrecompileTesterExt, EvmResult}; -use sp_core::H160; - -pub struct PrecompileSet; - -#[precompile_utils_macro::precompile] -#[precompile::precompile_set] -impl PrecompileSet { - #[precompile::discriminant] - fn discriminant(_: H160) -> Option<()> { - Some(()) - } - - #[precompile::public("default()")] - fn default(_: (), _: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } - - #[precompile::public("view()")] - #[precompile::view] - fn view(_: (), _: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } - - #[precompile::public("payable()")] - #[precompile::payable] - fn payable(_: (), _: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } -} - -fn main() { - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::default {}) - .with_value(1) - .execute_reverts(|output| output == b"Function is not payable"); - - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::default {}) - .with_static_call(true) - .execute_reverts(|output| output == b"Can't call non-static function in static context"); - - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::view {}) - .with_value(1) - .execute_reverts(|output| output == b"Function is not payable"); - - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::view {}) - .with_static_call(true) - .execute_returns(()); - - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::payable {}) - .with_value(1) - .execute_returns(()); - - PrecompileSet - .prepare_test([0u8; 20], [0u8; 20], PrecompileSetCall::payable {}) - .with_static_call(true) - .execute_reverts(|output| output == b"Can't call non-static function in static context"); -} diff --git a/precompiles/utils/macro/tests/tests.rs b/precompiles/utils/macro/tests/tests.rs deleted file mode 100644 index dd456be727..0000000000 --- a/precompiles/utils/macro/tests/tests.rs +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use sp_core_hashing::keccak_256; - -#[test] -fn test_keccak256() { - assert_eq!( - &precompile_utils_macro_v2::keccak256!(""), - keccak_256(b"").as_slice(), - ); - assert_eq!( - &precompile_utils_macro_v2::keccak256!("toto()"), - keccak_256(b"toto()").as_slice(), - ); - assert_ne!( - &precompile_utils_macro_v2::keccak256!("toto()"), - keccak_256(b"tata()").as_slice(), - ); -} - -#[test] -#[ignore] -fn ui() { - let t = trybuild::TestCases::new(); - t.compile_fail("tests/compile-fail/**/*.rs"); - t.pass("tests/pass/**/*.rs"); -} - -// Cargo expand is not supported on stable rust -#[test] -#[ignore] -fn expand() { - // Use `expand` to update the expansions - // Replace it with `expand_without_refresh` afterward so that - // CI checks the expension don't change - - // macrotest::expand("tests/expand/**/*.rs"); - macrotest::expand_without_refresh("tests/expand/**/*.rs"); -} diff --git a/precompiles/utils/src/evm/costs.rs b/precompiles/utils/src/evm/costs.rs deleted file mode 100644 index 34fb2a4265..0000000000 --- a/precompiles/utils/src/evm/costs.rs +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Cost calculations. -//! TODO: PR EVM to make those cost calculations public. - -use crate::EvmResult; -use fp_evm::{ExitError, PrecompileFailure}; -use sp_core::U256; - -pub fn log_costs(topics: usize, data_len: usize) -> EvmResult { - // Cost calculation is copied from EVM code that is not publicly exposed by the crates. - // https://github.com/rust-blockchain/evm/blob/master/gasometer/src/costs.rs#L148 - - const G_LOG: u64 = 375; - const G_LOGDATA: u64 = 8; - const G_LOGTOPIC: u64 = 375; - - let topic_cost = G_LOGTOPIC - .checked_mul(topics as u64) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })?; - - let data_cost = G_LOGDATA - .checked_mul(data_len as u64) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })?; - - G_LOG - .checked_add(topic_cost) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })? - .checked_add(data_cost) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }) -} - -// Compute the cost of doing a subcall. -// Some parameters cannot be known in advance, so we estimate the worst possible cost. -pub fn call_cost(value: U256, config: &evm::Config) -> u64 { - // Copied from EVM code since not public. - pub const G_CALLVALUE: u64 = 9000; - pub const G_NEWACCOUNT: u64 = 25000; - - fn address_access_cost(is_cold: bool, regular_value: u64, config: &evm::Config) -> u64 { - if config.increase_state_access_gas { - if is_cold { - config.gas_account_access_cold - } else { - config.gas_storage_read_warm - } - } else { - regular_value - } - } - - fn xfer_cost(is_call_or_callcode: bool, transfers_value: bool) -> u64 { - if is_call_or_callcode && transfers_value { - G_CALLVALUE - } else { - 0 - } - } - - fn new_cost( - is_call_or_staticcall: bool, - new_account: bool, - transfers_value: bool, - config: &evm::Config, - ) -> u64 { - let eip161 = !config.empty_considered_exists; - if is_call_or_staticcall { - if eip161 { - if transfers_value && new_account { - G_NEWACCOUNT - } else { - 0 - } - } else if new_account { - G_NEWACCOUNT - } else { - 0 - } - } else { - 0 - } - } - - let transfers_value = value != U256::default(); - let is_cold = true; - let is_call_or_callcode = true; - let is_call_or_staticcall = true; - let new_account = true; - - address_access_cost(is_cold, config.gas_call, config) - + xfer_cost(is_call_or_callcode, transfers_value) - + new_cost(is_call_or_staticcall, new_account, transfers_value, config) -} diff --git a/precompiles/utils/src/evm/handle.rs b/precompiles/utils/src/evm/handle.rs deleted file mode 100644 index 1ed775348f..0000000000 --- a/precompiles/utils/src/evm/handle.rs +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - solidity::{ - codec::Reader, - modifier::FunctionModifier, - revert::{MayRevert, RevertReason}, - }, - EvmResult, -}; -use fp_evm::{Log, PrecompileHandle}; - -pub trait PrecompileHandleExt: PrecompileHandle { - /// Record cost of one DB read manually. - /// The max encoded lenght of the data that will be read should be provided. - fn record_db_read( - &mut self, - data_max_encoded_len: usize, - ) -> Result<(), evm::ExitError>; - - /// Record cost of a log manually. - /// This can be useful to record log costs early when their content have static size. - fn record_log_costs_manual(&mut self, topics: usize, data_len: usize) -> EvmResult; - - /// Record cost of logs. - fn record_log_costs(&mut self, logs: &[&Log]) -> EvmResult; - - /// Check that a function call is compatible with the context it is - /// called into. - fn check_function_modifier(&self, modifier: FunctionModifier) -> MayRevert; - - /// Read the selector from the input data. - fn read_u32_selector(&self) -> MayRevert; - - /// Returns a reader of the input, skipping the selector. - fn read_after_selector(&self) -> MayRevert; -} - -impl PrecompileHandleExt for T { - fn record_db_read( - &mut self, - data_max_encoded_len: usize, - ) -> Result<(), evm::ExitError> { - self.record_cost(crate::prelude::RuntimeHelper::::db_read_gas_cost())?; - // TODO: record ref time when precompile will be benchmarked - self.record_external_cost(None, Some(data_max_encoded_len as u64), None) - } - - /// Record cost of a log manualy. - /// This can be useful to record log costs early when their content have static size. - fn record_log_costs_manual(&mut self, topics: usize, data_len: usize) -> EvmResult { - self.record_cost(crate::evm::costs::log_costs(topics, data_len)?)?; - - Ok(()) - } - - /// Record cost of logs. - fn record_log_costs(&mut self, logs: &[&Log]) -> EvmResult { - for log in logs { - self.record_log_costs_manual(log.topics.len(), log.data.len())?; - } - - Ok(()) - } - - /// Check that a function call is compatible with the context it is - /// called into. - fn check_function_modifier(&self, modifier: FunctionModifier) -> MayRevert { - crate::solidity::modifier::check_function_modifier( - self.context(), - self.is_static(), - modifier, - ) - } - - /// Read the selector from the input data as u32. - fn read_u32_selector(&self) -> MayRevert { - crate::solidity::codec::selector(self.input()) - .ok_or(RevertReason::read_out_of_bounds("selector").into()) - } - - /// Returns a reader of the input, skipping the selector. - fn read_after_selector(&self) -> MayRevert { - Reader::new_skip_selector(self.input()) - } -} - -environmental::environmental!(EVM_CONTEXT: trait PrecompileHandle); - -pub fn using_precompile_handle<'a, R, F: FnOnce() -> R>( - precompile_handle: &'a mut dyn PrecompileHandle, - mutator: F, -) -> R { - // # Safety - // - // unsafe rust does not mean unsafe, but "the compiler cannot guarantee the safety of the - // memory". - // - // The only risk here is that the lifetime 'a comes to its end while the global variable - // `EVM_CONTEXT` still contains the reference to the precompile handle. - // The `using` method guarantee that it can't happen because the global variable is freed right - // after the execution of the `mutator` closure (whatever the result of the execution). - unsafe { - EVM_CONTEXT::using( - core::mem::transmute::<&'a mut dyn PrecompileHandle, &'static mut dyn PrecompileHandle>( - precompile_handle, - ), - mutator, - ) - } -} - -pub fn with_precompile_handle R>(f: F) -> Option { - EVM_CONTEXT::with(|precompile_handle| f(precompile_handle)) -} - -#[cfg(test)] -mod tests { - use super::*; - - struct MockPrecompileHandle; - impl PrecompileHandle for MockPrecompileHandle { - fn call( - &mut self, - _: sp_core::H160, - _: Option, - _: Vec, - _: Option, - _: bool, - _: &evm::Context, - ) -> (evm::ExitReason, Vec) { - unimplemented!() - } - - fn record_cost(&mut self, _: u64) -> Result<(), evm::ExitError> { - unimplemented!() - } - - fn remaining_gas(&self) -> u64 { - unimplemented!() - } - - fn log( - &mut self, - _: sp_core::H160, - _: Vec, - _: Vec, - ) -> Result<(), evm::ExitError> { - unimplemented!() - } - - fn code_address(&self) -> sp_core::H160 { - unimplemented!() - } - - fn input(&self) -> &[u8] { - unimplemented!() - } - - fn context(&self) -> &evm::Context { - unimplemented!() - } - - fn is_static(&self) -> bool { - true - } - - fn gas_limit(&self) -> Option { - unimplemented!() - } - - fn record_external_cost( - &mut self, - _ref_time: Option, - _proof_size: Option, - _storage_growth: Option, - ) -> Result<(), fp_evm::ExitError> { - Ok(()) - } - - fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} - } - - #[test] - fn with_precompile_handle_without_context() { - assert_eq!(with_precompile_handle(|_| {}), None); - } - - #[test] - fn with_precompile_handle_with_context() { - let mut precompile_handle = MockPrecompileHandle; - - assert_eq!( - using_precompile_handle(&mut precompile_handle, || with_precompile_handle( - |handle| handle.is_static() - )), - Some(true) - ); - } -} diff --git a/precompiles/utils/src/evm/logs.rs b/precompiles/utils/src/evm/logs.rs deleted file mode 100644 index 0ce6367f40..0000000000 --- a/precompiles/utils/src/evm/logs.rs +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::EvmResult; -use pallet_evm::{Log, PrecompileHandle}; -use sp_core::{H160, H256}; -use sp_std::{vec, vec::Vec}; - -/// Create a 0-topic log. -#[must_use] -pub fn log0(address: impl Into, data: impl Into>) -> Log { - Log { - address: address.into(), - topics: vec![], - data: data.into(), - } -} - -/// Create a 1-topic log. -#[must_use] -pub fn log1(address: impl Into, topic0: impl Into, data: impl Into>) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into()], - data: data.into(), - } -} - -/// Create a 2-topics log. -#[must_use] -pub fn log2( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into()], - data: data.into(), - } -} - -/// Create a 3-topics log. -#[must_use] -pub fn log3( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - topic2: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into(), topic2.into()], - data: data.into(), - } -} - -/// Create a 4-topics log. -#[must_use] -pub fn log4( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - topic2: impl Into, - topic3: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into(), topic2.into(), topic3.into()], - data: data.into(), - } -} - -/// Extension trait allowing to record logs into a PrecompileHandle. -pub trait LogExt { - fn record(self, handle: &mut impl PrecompileHandle) -> EvmResult; - - fn compute_cost(&self) -> EvmResult; -} - -impl LogExt for Log { - fn record(self, handle: &mut impl PrecompileHandle) -> EvmResult { - handle.log(self.address, self.topics, self.data)?; - Ok(()) - } - - fn compute_cost(&self) -> EvmResult { - crate::evm::costs::log_costs(self.topics.len(), self.data.len()) - } -} diff --git a/precompiles/utils/src/evm/mod.rs b/precompiles/utils/src/evm/mod.rs deleted file mode 100644 index ffd1ef42e0..0000000000 --- a/precompiles/utils/src/evm/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -pub mod costs; -pub mod handle; -pub mod logs; diff --git a/precompiles/utils/src/lib.rs b/precompiles/utils/src/lib.rs deleted file mode 100644 index 10fd3cad5f..0000000000 --- a/precompiles/utils/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; - -// Allows to use inside this crate `solidity::Codec` derive macro,which depends on -// `precompile_utils` being in the list of imported crates. -extern crate self as precompile_utils; - -pub mod evm; -pub mod precompile_set; -pub mod substrate; - -pub mod solidity; - -#[cfg(feature = "testing")] -pub mod testing; - -use fp_evm::PrecompileFailure; - -// pub mod data; - -// pub use data::{solidity::Codec, Reader, Writer}; -pub use fp_evm::Precompile; -pub use precompile_utils_macro_v2::{keccak256, precompile, precompile_name_from_address}; - -/// Alias for Result returning an EVM precompile error. -pub type EvmResult = Result; - -pub mod prelude { - pub use { - crate::{ - evm::{ - handle::PrecompileHandleExt, - logs::{log0, log1, log2, log3, log4, LogExt}, - }, - precompile_set::DiscriminantResult, - solidity::{ - // We export solidity itself to encourage using `solidity::Codec` to avoid confusion - // with parity_scale_codec, - self, - codec::{ - Address, - BoundedBytes, - BoundedString, - BoundedVec, - // Allow usage of Codec methods while not exporting the name directly. - Codec as _, - Convert, - UnboundedBytes, - UnboundedString, - }, - revert::{ - revert, BacktraceExt, InjectBacktrace, MayRevert, Revert, RevertExt, - RevertReason, - }, - }, - substrate::{RuntimeHelper, TryDispatchError}, - EvmResult, - }, - alloc::string::String, - pallet_evm::{PrecompileHandle, PrecompileOutput}, - precompile_utils_macro_v2::{keccak256, precompile}, - }; -} diff --git a/precompiles/utils/src/precompile_set.rs b/precompiles/utils/src/precompile_set.rs deleted file mode 100644 index 57afdf42cb..0000000000 --- a/precompiles/utils/src/precompile_set.rs +++ /dev/null @@ -1,1097 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Provide utils to assemble precompiles and precompilesets into a -//! final precompile set with security checks. All security checks are enabled by -//! default and must be disabled explicely throught type annotations. - -use crate::{ - evm::handle::PrecompileHandleExt, - solidity::{codec::String, revert::revert}, - EvmResult, -}; -use fp_evm::{ - ExitError, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, - PrecompileResult, PrecompileSet, -}; -use frame_support::pallet_prelude::Get; -use impl_trait_for_tuples::impl_for_tuples; -use sp_core::{H160, H256}; -use sp_std::{ - cell::RefCell, collections::btree_map::BTreeMap, marker::PhantomData, ops::RangeInclusive, vec, - vec::Vec, -}; - -/// Trait representing checks that can be made on a precompile call. -/// Types implementing this trait are made to be chained in a tuple. -/// -/// For that reason every method returns an Option, None meaning that -/// the implementor have no constraint and the decision is left to -/// latter elements in the chain. If None is returned by all elements of -/// the chain then sensible defaults are used. -/// -/// Both `PrecompileAt` and `PrecompileSetStartingWith` have a type parameter that must -/// implement this trait to configure the checks of the precompile(set) it represents. -pub trait PrecompileChecks { - #[inline(always)] - /// Is there a limit to the amount of recursions this precompile - /// can make using subcalls? 0 means this specific precompile will not - /// be callable as a subcall of itself, 1 will allow one level of recursion, - /// etc... - /// - /// If all checks return None, defaults to `Some(0)` (no recursion allowed). - fn recursion_limit() -> Option> { - None - } - - #[inline(always)] - /// Does this precompile supports being called with DELEGATECALL or CALLCODE? - /// - /// If all checks return None, defaults to `false`. - fn accept_delegate_call() -> Option { - None - } - - #[inline(always)] - /// Is this precompile callable by a smart contract? - /// - /// If all checks return None, defaults to `false`. - fn callable_by_smart_contract(_caller: H160, _called_selector: Option) -> Option { - None - } - - #[inline(always)] - /// Is this precompile callable by a precompile? - /// - /// If all checks return None, defaults to `false`. - fn callable_by_precompile(_caller: H160, _called_selector: Option) -> Option { - None - } - - #[inline(always)] - /// Is this precompile able to do subcalls? - /// - /// If all checks return None, defaults to `false`. - fn allow_subcalls() -> Option { - None - } - - /// Summarize the checks when being called by a smart contract. - fn callable_by_smart_contract_summary() -> Option { - None - } - - /// Summarize the checks when being called by a precompile. - fn callable_by_precompile_summary() -> Option { - None - } -} - -#[derive(Debug, Clone)] -pub enum DiscriminantResult { - Some(T, u64), - None(u64), - OutOfGas, -} - -impl From> for IsPrecompileResult { - fn from(val: DiscriminantResult) -> Self { - match val { - DiscriminantResult::::Some(_, extra_cost) => IsPrecompileResult::Answer { - is_precompile: true, - extra_cost, - }, - DiscriminantResult::::None(extra_cost) => IsPrecompileResult::Answer { - is_precompile: false, - extra_cost, - }, - DiscriminantResult::::OutOfGas => IsPrecompileResult::OutOfGas, - } - } -} - -#[derive(Debug, Clone)] -#[cfg_attr(feature = "testing", derive(serde::Serialize, serde::Deserialize))] -pub enum PrecompileKind { - Single(H160), - Prefixed(Vec), -} - -#[derive(Debug, Clone)] -#[cfg_attr(feature = "testing", derive(serde::Serialize, serde::Deserialize))] -pub struct PrecompileCheckSummary { - pub name: Option, - pub precompile_kind: PrecompileKind, - pub recursion_limit: Option, - pub accept_delegate_call: bool, - pub callable_by_smart_contract: String, - pub callable_by_precompile: String, -} - -#[impl_for_tuples(0, 20)] -impl PrecompileChecks for Tuple { - #[inline(always)] - fn recursion_limit() -> Option> { - for_tuples!(#( - if let Some(check) = Tuple::recursion_limit() { - return Some(check); - } - )*); - - None - } - - #[inline(always)] - fn accept_delegate_call() -> Option { - for_tuples!(#( - if let Some(check) = Tuple::accept_delegate_call() { - return Some(check); - } - )*); - - None - } - - #[inline(always)] - fn callable_by_smart_contract(caller: H160, called_selector: Option) -> Option { - for_tuples!(#( - if let Some(check) = Tuple::callable_by_smart_contract(caller, called_selector) { - return Some(check); - } - )*); - - None - } - - #[inline(always)] - fn callable_by_precompile(caller: H160, called_selector: Option) -> Option { - for_tuples!(#( - if let Some(check) = Tuple::callable_by_precompile(caller, called_selector) { - return Some(check); - } - )*); - - None - } - - #[inline(always)] - fn allow_subcalls() -> Option { - for_tuples!(#( - if let Some(check) = Tuple::allow_subcalls() { - return Some(check); - } - )*); - - None - } - - fn callable_by_smart_contract_summary() -> Option { - for_tuples!(#( - if let Some(check) = Tuple::callable_by_smart_contract_summary() { - return Some(check); - } - )*); - - None - } - - fn callable_by_precompile_summary() -> Option { - for_tuples!(#( - if let Some(check) = Tuple::callable_by_precompile_summary() { - return Some(check); - } - )*); - - None - } -} - -/// Precompile can be called using DELEGATECALL/CALLCODE. -pub struct AcceptDelegateCall; - -impl PrecompileChecks for AcceptDelegateCall { - #[inline(always)] - fn accept_delegate_call() -> Option { - Some(true) - } -} - -/// Precompile is able to do subcalls with provided nesting limit. -pub struct SubcallWithMaxNesting; - -impl PrecompileChecks for SubcallWithMaxNesting { - #[inline(always)] - fn recursion_limit() -> Option> { - Some(Some(R)) - } - - #[inline(always)] - fn allow_subcalls() -> Option { - Some(true) - } -} - -pub trait SelectorFilter { - fn is_allowed(_caller: H160, _selector: Option) -> bool; - - fn description() -> String; -} -pub struct ForAllSelectors; -impl SelectorFilter for ForAllSelectors { - fn is_allowed(_caller: H160, _selector: Option) -> bool { - true - } - - fn description() -> String { - "Allowed for all selectors and callers".into() - } -} - -pub struct OnlyFrom(PhantomData); -impl> SelectorFilter for OnlyFrom { - fn is_allowed(caller: H160, _selector: Option) -> bool { - caller == T::get() - } - - fn description() -> String { - alloc::format!("Allowed for all selectors only if called from {}", T::get()) - } -} - -pub struct CallableByContract(PhantomData); - -impl PrecompileChecks for CallableByContract { - #[inline(always)] - fn callable_by_smart_contract(caller: H160, called_selector: Option) -> Option { - Some(T::is_allowed(caller, called_selector)) - } - - fn callable_by_smart_contract_summary() -> Option { - Some(T::description()) - } -} - -/// Precompiles are allowed to call this precompile. -pub struct CallableByPrecompile(PhantomData); - -impl PrecompileChecks for CallableByPrecompile { - #[inline(always)] - fn callable_by_precompile(caller: H160, called_selector: Option) -> Option { - Some(T::is_allowed(caller, called_selector)) - } - - fn callable_by_precompile_summary() -> Option { - Some(T::description()) - } -} - -/// The type of EVM address. -#[derive(PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum AddressType { - /// The code stored at the address is less than 5 bytes, but not well known. - Unknown, - /// No code is stored at the address, therefore is EOA. - EOA, - /// The 5-byte magic constant for a precompile is stored at the address. - Precompile, - /// The code is greater than 5-bytes, potentially a Smart Contract. - Contract, -} - -/// Retrieves the type of address demarcated by `AddressType`. -pub fn get_address_type( - handle: &mut impl PrecompileHandle, - address: H160, -) -> Result { - // AccountCodesMetadata: - // Blake2128(16) + H160(20) + CodeMetadata(40) - handle.record_db_read::(76)?; - let code_len = pallet_evm::Pallet::::account_code_metadata(address).size; - - // 0 => either EOA or precompile without dummy code - if code_len == 0 { - return Ok(AddressType::EOA); - } - - // dummy code is 5 bytes long, so any other len means it is a contract. - if code_len != 5 { - return Ok(AddressType::Contract); - } - - // check code matches dummy code - handle.record_db_read::(code_len as usize)?; - let code = pallet_evm::AccountCodes::::get(address); - if code == [0x60, 0x00, 0x60, 0x00, 0xfd] { - return Ok(AddressType::Precompile); - } - - Ok(AddressType::Unknown) -} - -fn is_address_eoa_or_precompile( - handle: &mut impl PrecompileHandle, - address: H160, -) -> Result { - match get_address_type::(handle, address)? { - AddressType::EOA | AddressType::Precompile => Ok(true), - _ => Ok(false), - } -} - -/// Common checks for precompile and precompile sets. -/// Don't contain recursion check as precompile sets have recursion check for each member. -fn common_checks( - handle: &mut impl PrecompileHandle, -) -> EvmResult<()> { - let code_address = handle.code_address(); - let caller = handle.context().caller; - - // Check DELEGATECALL config. - let accept_delegate_call = C::accept_delegate_call().unwrap_or(false); - if !accept_delegate_call && code_address != handle.context().address { - return Err(revert("Cannot be called with DELEGATECALL or CALLCODE")); - } - - // Extract which selector is called. - let selector = handle.input().get(0..4).map(|bytes| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(bytes); - u32::from_be_bytes(buffer) - }); - - // Is this selector callable from a smart contract? - let callable_by_smart_contract = - C::callable_by_smart_contract(caller, selector).unwrap_or(false); - if !callable_by_smart_contract && !is_address_eoa_or_precompile::(handle, caller)? { - return Err(revert("Function not callable by smart contracts")); - } - - // Is this selector callable from a precompile? - let callable_by_precompile = C::callable_by_precompile(caller, selector).unwrap_or(false); - if !callable_by_precompile && is_precompile_or_fail::(caller, handle.remaining_gas())? { - return Err(revert("Function not callable by precompiles")); - } - - Ok(()) -} - -pub fn is_precompile_or_fail(address: H160, gas: u64) -> EvmResult { - match ::PrecompilesValue::get().is_precompile(address, gas) { - IsPrecompileResult::Answer { is_precompile, .. } => Ok(is_precompile), - IsPrecompileResult::OutOfGas => Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }), - } -} - -pub struct AddressU64; -impl Get for AddressU64 { - #[inline(always)] - fn get() -> H160 { - H160::from_low_u64_be(N) - } -} - -pub struct RestrictiveHandle<'a, H> { - handle: &'a mut H, - allow_subcalls: bool, -} - -impl<'a, H: PrecompileHandle> PrecompileHandle for RestrictiveHandle<'a, H> { - fn call( - &mut self, - address: H160, - transfer: Option, - input: Vec, - target_gas: Option, - is_static: bool, - context: &evm::Context, - ) -> (evm::ExitReason, Vec) { - if !self.allow_subcalls { - return ( - evm::ExitReason::Revert(evm::ExitRevert::Reverted), - crate::solidity::revert::revert_as_bytes("subcalls disabled for this precompile"), - ); - } - - self.handle - .call(address, transfer, input, target_gas, is_static, context) - } - - fn record_cost(&mut self, cost: u64) -> Result<(), evm::ExitError> { - self.handle.record_cost(cost) - } - - fn remaining_gas(&self) -> u64 { - self.handle.remaining_gas() - } - - fn log( - &mut self, - address: H160, - topics: Vec, - data: Vec, - ) -> Result<(), evm::ExitError> { - self.handle.log(address, topics, data) - } - - fn code_address(&self) -> H160 { - self.handle.code_address() - } - - fn input(&self) -> &[u8] { - self.handle.input() - } - - fn context(&self) -> &evm::Context { - self.handle.context() - } - - fn is_static(&self) -> bool { - self.handle.is_static() - } - - fn gas_limit(&self) -> Option { - self.handle.gas_limit() - } - - fn record_external_cost( - &mut self, - ref_time: Option, - proof_size: Option, - storage_growth: Option, - ) -> Result<(), ExitError> { - self.handle - .record_external_cost(ref_time, proof_size, storage_growth) - } - - fn refund_external_cost(&mut self, ref_time: Option, proof_size: Option) { - self.handle.refund_external_cost(ref_time, proof_size) - } -} - -/// Allows to know if a precompile is active or not. -/// This allows to detect deactivated precompile, that are still considered precompiles by -/// the EVM but that will always revert when called. -pub trait IsActivePrecompile { - /// Is the provided address an active precompile, a precompile that has - /// not be deactivated. Note that a deactivated precompile is still considered a precompile - /// for the EVM, but it will always revert when called. - fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult; -} - -// INDIVIDUAL PRECOMPILE(SET) - -/// A fragment of a PrecompileSet. Should be implemented as is it -/// was a PrecompileSet containing only the precompile(set) it wraps. -/// They can be combined into a real PrecompileSet using `PrecompileSetBuilder`. -pub trait PrecompileSetFragment { - /// Instanciate the fragment. - fn new() -> Self; - - /// Execute the fragment. - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option; - - /// Is the provided address a precompile in this fragment? - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult; - - /// Return the list of addresses covered by this fragment. - fn used_addresses(&self) -> Vec; - - /// Summarize - fn summarize_checks(&self) -> Vec; -} - -/// Wraps a stateless precompile: a type implementing the `Precompile` trait. -/// Type parameters allow to define: -/// - A: The address of the precompile -/// - R: The recursion limit (defaults to 1) -/// - D: If DELEGATECALL is supported (default to no) -pub struct PrecompileAt { - current_recursion_level: RefCell, - _phantom: PhantomData<(A, P, C)>, -} - -impl PrecompileSetFragment for PrecompileAt -where - A: Get, - P: Precompile, - C: PrecompileChecks, -{ - #[inline(always)] - fn new() -> Self { - Self { - current_recursion_level: RefCell::new(0), - _phantom: PhantomData, - } - } - - #[inline(always)] - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - let code_address = handle.code_address(); - - // Check if this is the address of the precompile. - if A::get() != code_address { - return None; - } - - // Perform common checks. - if let Err(err) = common_checks::(handle) { - return Some(Err(err)); - } - - // Check and increase recursion level if needed. - let recursion_limit = C::recursion_limit().unwrap_or(Some(0)); - if let Some(max_recursion_level) = recursion_limit { - match self.current_recursion_level.try_borrow_mut() { - Ok(mut recursion_level) => { - if *recursion_level > max_recursion_level { - return Some(Err(revert("Precompile is called with too high nesting"))); - } - - *recursion_level += 1; - } - // We don't hold the borrow and are in single-threaded code, thus we should - // not be able to fail borrowing in nested calls. - Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))), - } - } - - // Subcall protection. - let allow_subcalls = C::allow_subcalls().unwrap_or(false); - let mut handle = RestrictiveHandle { - handle, - allow_subcalls, - }; - - let res = P::execute(&mut handle); - - // Decrease recursion level if needed. - if recursion_limit.is_some() { - match self.current_recursion_level.try_borrow_mut() { - Ok(mut recursion_level) => { - *recursion_level -= 1; - } - // We don't hold the borrow and are in single-threaded code, thus we should - // not be able to fail borrowing in nested calls. - Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))), - } - } - - Some(res) - } - - #[inline(always)] - fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: address == A::get(), - extra_cost: 0, - } - } - - #[inline(always)] - fn used_addresses(&self) -> Vec { - vec![A::get()] - } - - fn summarize_checks(&self) -> Vec { - vec![PrecompileCheckSummary { - name: None, - precompile_kind: PrecompileKind::Single(A::get()), - recursion_limit: C::recursion_limit().unwrap_or(Some(0)), - accept_delegate_call: C::accept_delegate_call().unwrap_or(false), - callable_by_smart_contract: C::callable_by_smart_contract_summary() - .unwrap_or_else(|| "Not callable".into()), - callable_by_precompile: C::callable_by_precompile_summary() - .unwrap_or_else(|| "Not callable".into()), - }] - } -} - -impl IsActivePrecompile for PrecompileAt -where - A: Get, -{ - #[inline(always)] - fn is_active_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: address == A::get(), - extra_cost: 0, - } - } -} - -/// Wraps an inner PrecompileSet with all its addresses starting with -/// a common prefix. -/// Type parameters allow to define: -/// - A: The common prefix -/// - D: If DELEGATECALL is supported (default to no) -pub struct PrecompileSetStartingWith { - precompile_set: P, - current_recursion_level: RefCell>, - _phantom: PhantomData<(A, C)>, -} - -impl PrecompileSetFragment for PrecompileSetStartingWith -where - A: Get<&'static [u8]>, - P: PrecompileSet + Default, - C: PrecompileChecks, -{ - #[inline(always)] - fn new() -> Self { - Self { - precompile_set: P::default(), - current_recursion_level: RefCell::new(BTreeMap::new()), - _phantom: PhantomData, - } - } - - #[inline(always)] - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - let code_address = handle.code_address(); - if !is_precompile_or_fail::(code_address, handle.remaining_gas()).ok()? { - return None; - } - // Perform common checks. - if let Err(err) = common_checks::(handle) { - return Some(Err(err)); - } - - // Check and increase recursion level if needed. - let recursion_limit = C::recursion_limit().unwrap_or(Some(0)); - if let Some(max_recursion_level) = recursion_limit { - match self.current_recursion_level.try_borrow_mut() { - Ok(mut recursion_level_map) => { - let recursion_level = recursion_level_map.entry(code_address).or_insert(0); - - if *recursion_level > max_recursion_level { - return Some(Err(revert("Precompile is called with too high nesting"))); - } - - *recursion_level += 1; - } - // We don't hold the borrow and are in single-threaded code, thus we should - // not be able to fail borrowing in nested calls. - Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))), - } - } - - // Subcall protection. - let allow_subcalls = C::allow_subcalls().unwrap_or(false); - let mut handle = RestrictiveHandle { - handle, - allow_subcalls, - }; - - let res = self.precompile_set.execute(&mut handle); - - // Decrease recursion level if needed. - if recursion_limit.is_some() { - match self.current_recursion_level.try_borrow_mut() { - Ok(mut recursion_level_map) => { - let recursion_level = match recursion_level_map.get_mut(&code_address) { - Some(recursion_level) => recursion_level, - None => return Some(Err(revert("Couldn't retreive precompile nesting"))), - }; - - *recursion_level -= 1; - } - // We don't hold the borrow and are in single-threaded code, thus we should - // not be able to fail borrowing in nested calls. - Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))), - } - } - - res - } - - #[inline(always)] - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - if address.as_bytes().starts_with(A::get()) { - return self.precompile_set.is_precompile(address, gas); - } - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } - - #[inline(always)] - fn used_addresses(&self) -> Vec { - // TODO: We currently can't get the list of used addresses. - vec![] - } - - fn summarize_checks(&self) -> Vec { - let prefix = A::get(); - - vec![PrecompileCheckSummary { - name: None, - precompile_kind: PrecompileKind::Prefixed(prefix.to_vec()), - recursion_limit: C::recursion_limit().unwrap_or(Some(0)), - accept_delegate_call: C::accept_delegate_call().unwrap_or(false), - callable_by_smart_contract: C::callable_by_smart_contract_summary() - .unwrap_or_else(|| "Not callable".into()), - callable_by_precompile: C::callable_by_precompile_summary() - .unwrap_or_else(|| "Not callable".into()), - }] - } -} - -impl IsActivePrecompile for PrecompileSetStartingWith -where - Self: PrecompileSetFragment, -{ - #[inline(always)] - fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - self.is_precompile(address, gas) - } -} - -/// Make a precompile that always revert. -/// Can be useful when writing tests. -pub struct RevertPrecompile(PhantomData); - -impl PrecompileSetFragment for RevertPrecompile -where - A: Get, -{ - #[inline(always)] - fn new() -> Self { - Self(PhantomData) - } - - #[inline(always)] - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - if A::get() == handle.code_address() { - Some(Err(revert("revert"))) - } else { - None - } - } - - #[inline(always)] - fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: address == A::get(), - extra_cost: 0, - } - } - - #[inline(always)] - fn used_addresses(&self) -> Vec { - vec![A::get()] - } - - fn summarize_checks(&self) -> Vec { - vec![PrecompileCheckSummary { - name: None, - precompile_kind: PrecompileKind::Single(A::get()), - recursion_limit: Some(0), - accept_delegate_call: true, - callable_by_smart_contract: "Reverts in all cases".into(), - callable_by_precompile: "Reverts in all cases".into(), - }] - } -} - -impl IsActivePrecompile for RevertPrecompile { - #[inline(always)] - fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: true, - extra_cost: 0, - } - } -} - -/// A precompile that was removed from a precompile set. -/// Still considered a precompile but is inactive and always revert. -pub struct RemovedPrecompileAt(PhantomData); -impl PrecompileSetFragment for RemovedPrecompileAt -where - A: Get, -{ - #[inline(always)] - fn new() -> Self { - Self(PhantomData) - } - - #[inline(always)] - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - if A::get() == handle.code_address() { - Some(Err(revert("Removed precompile"))) - } else { - None - } - } - - #[inline(always)] - fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: address == A::get(), - extra_cost: 0, - } - } - - #[inline(always)] - fn used_addresses(&self) -> Vec { - vec![A::get()] - } - - fn summarize_checks(&self) -> Vec { - vec![PrecompileCheckSummary { - name: None, - precompile_kind: PrecompileKind::Single(A::get()), - recursion_limit: Some(0), - accept_delegate_call: true, - callable_by_smart_contract: "Reverts in all cases".into(), - callable_by_precompile: "Reverts in all cases".into(), - }] - } -} - -impl IsActivePrecompile for RemovedPrecompileAt { - #[inline(always)] - fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } -} - -// COMPOSITION OF PARTS -#[impl_for_tuples(1, 100)] -impl PrecompileSetFragment for Tuple { - #[inline(always)] - fn new() -> Self { - (for_tuples!(#( - Tuple::new() - ),*)) - } - - #[inline(always)] - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - for_tuples!(#( - if let Some(res) = self.Tuple.execute::(handle) { - return Some(res); - } - )*); - - None - } - - #[inline(always)] - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - for_tuples!(#( - if let IsPrecompileResult::Answer { - is_precompile: true, - .. - } = self.Tuple.is_precompile(address, gas) { return IsPrecompileResult::Answer { - is_precompile: true, - extra_cost: 0, - } - }; - )*); - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } - - #[inline(always)] - fn used_addresses(&self) -> Vec { - let mut used_addresses = vec![]; - - for_tuples!(#( - let mut inner = self.Tuple.used_addresses(); - used_addresses.append(&mut inner); - )*); - - used_addresses - } - - fn summarize_checks(&self) -> Vec { - let mut checks = Vec::new(); - - for_tuples!(#( - let mut inner = self.Tuple.summarize_checks(); - checks.append(&mut inner); - )*); - - checks - } -} - -#[impl_for_tuples(1, 100)] -impl IsActivePrecompile for Tuple { - #[inline(always)] - fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - for_tuples!(#( - if let IsPrecompileResult::Answer { - is_precompile: true, - .. - } = self.Tuple.is_active_precompile(address, gas) { return IsPrecompileResult::Answer { - is_precompile: true, - extra_cost: 0, - } }; - )*); - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } -} - -/// Wraps a precompileset fragment into a range, and will skip processing it if the address -/// is out of the range. -pub struct PrecompilesInRangeInclusive { - inner: P, - range: RangeInclusive, - _phantom: PhantomData, -} - -impl PrecompileSetFragment for PrecompilesInRangeInclusive<(S, E), P> -where - S: Get, - E: Get, - P: PrecompileSetFragment, -{ - fn new() -> Self { - Self { - inner: P::new(), - range: RangeInclusive::new(S::get(), E::get()), - _phantom: PhantomData, - } - } - - fn execute( - &self, - handle: &mut impl PrecompileHandle, - ) -> Option { - if self.range.contains(&handle.code_address()) { - self.inner.execute::(handle) - } else { - None - } - } - - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - if self.range.contains(&address) { - self.inner.is_precompile(address, gas) - } else { - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } - } - - fn used_addresses(&self) -> Vec { - self.inner.used_addresses() - } - - fn summarize_checks(&self) -> Vec { - self.inner.summarize_checks() - } -} - -impl IsActivePrecompile for PrecompilesInRangeInclusive<(S, E), P> -where - P: IsActivePrecompile, -{ - fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - if self.range.contains(&address) { - self.inner.is_active_precompile(address, gas) - } else { - IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } - } -} - -/// Wraps a tuple of `PrecompileSetFragment` to make a real `PrecompileSet`. -pub struct PrecompileSetBuilder { - inner: P, - _phantom: PhantomData, -} - -impl PrecompileSet for PrecompileSetBuilder { - fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { - self.inner.execute::(handle) - } - - fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - self.inner.is_precompile(address, gas) - } -} - -impl IsActivePrecompile for PrecompileSetBuilder { - fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult { - self.inner.is_active_precompile(address, gas) - } -} - -impl Default for PrecompileSetBuilder { - fn default() -> Self { - Self::new() - } -} - -impl PrecompileSetBuilder { - /// Create a new instance of the PrecompileSet. - pub fn new() -> Self { - Self { - inner: P::new(), - _phantom: PhantomData, - } - } - - /// Return the list of addresses contained in this PrecompileSet. - pub fn used_addresses() -> impl Iterator { - Self::new().inner.used_addresses().into_iter() - } - - pub fn summarize_checks(&self) -> Vec { - self.inner.summarize_checks() - } -} diff --git a/precompiles/utils/src/solidity/codec/bytes.rs b/precompiles/utils/src/solidity/codec/bytes.rs deleted file mode 100644 index 6c33458732..0000000000 --- a/precompiles/utils/src/solidity/codec/bytes.rs +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; -use alloc::borrow::ToOwned; -use sp_core::{ConstU32, Get}; - -type ConstU32Max = ConstU32<{ u32::MAX }>; - -pub type UnboundedBytes = BoundedBytesString; -pub type BoundedBytes = BoundedBytesString; - -pub type UnboundedString = BoundedBytesString; -pub type BoundedString = BoundedBytesString; - -trait Kind { - fn signature() -> String; -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BytesKind; - -impl Kind for BytesKind { - fn signature() -> String { - String::from("bytes") - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct StringKind; - -impl Kind for StringKind { - fn signature() -> String { - String::from("string") - } -} - -/// The `bytes/string` type of Solidity. -/// It is different from `Vec` which will be serialized with padding for each `u8` element -/// of the array, while `Bytes` is tightly packed. -#[derive(Debug)] -pub struct BoundedBytesString { - data: Vec, - _phantom: PhantomData<(K, S)>, -} - -impl> Clone for BoundedBytesString { - fn clone(&self) -> Self { - Self { - data: self.data.clone(), - _phantom: PhantomData, - } - } -} - -impl PartialEq> for BoundedBytesString { - fn eq(&self, other: &BoundedBytesString) -> bool { - self.data.eq(&other.data) - } -} - -impl Eq for BoundedBytesString {} - -impl> BoundedBytesString { - pub fn as_bytes(&self) -> &[u8] { - &self.data - } - - pub fn as_str(&self) -> Result<&str, sp_std::str::Utf8Error> { - sp_std::str::from_utf8(&self.data) - } -} - -impl> Codec for BoundedBytesString { - fn read(reader: &mut Reader) -> MayRevert { - let mut inner_reader = reader.read_pointer()?; - - // Read bytes/string size. - let array_size: usize = inner_reader - .read::() - .map_err(|_| RevertReason::read_out_of_bounds("length"))? - .try_into() - .map_err(|_| RevertReason::value_is_too_large("length"))?; - - if array_size > S::get() as usize { - return Err(RevertReason::value_is_too_large("length").into()); - } - - // Get valid range over the bytes data. - let range = inner_reader.move_cursor(array_size)?; - - let data = inner_reader - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds(K::signature()))?; - - let bytes = Self { - data: data.to_owned(), - _phantom: PhantomData, - }; - - Ok(bytes) - } - - fn write(writer: &mut Writer, value: Self) { - let value: Vec<_> = value.into(); - let length = value.len(); - - // Pad the data. - // Leave it as is if a multiple of 32, otherwise pad to next - // multiple or 32. - let chunks = length / 32; - let padded_size = match length % 32 { - 0 => chunks * 32, - _ => (chunks + 1) * 32, - }; - - let mut value = value.to_vec(); - value.resize(padded_size, 0); - - writer.write_pointer( - Writer::new() - .write(U256::from(length)) - .write_raw_bytes(&value) - .build(), - ); - } - - fn has_static_size() -> bool { - false - } - - fn signature() -> String { - K::signature() - } -} - -// BytesString <=> Vec/&[u8] - -impl From> for Vec { - fn from(value: BoundedBytesString) -> Self { - value.data - } -} - -impl From> for BoundedBytesString { - fn from(value: Vec) -> Self { - Self { - data: value, - _phantom: PhantomData, - } - } -} - -impl From<&[u8]> for BoundedBytesString { - fn from(value: &[u8]) -> Self { - Self { - data: value.to_vec(), - _phantom: PhantomData, - } - } -} - -impl From<[u8; N]> for BoundedBytesString { - fn from(value: [u8; N]) -> Self { - Self { - data: value.to_vec(), - _phantom: PhantomData, - } - } -} - -impl From<&[u8; N]> for BoundedBytesString { - fn from(value: &[u8; N]) -> Self { - Self { - data: value.to_vec(), - _phantom: PhantomData, - } - } -} - -// BytesString <=> String/str - -impl TryFrom> for String { - type Error = alloc::string::FromUtf8Error; - - fn try_from(value: BoundedBytesString) -> Result { - alloc::string::String::from_utf8(value.data) - } -} - -impl From<&str> for BoundedBytesString { - fn from(value: &str) -> Self { - Self { - data: value.as_bytes().into(), - _phantom: PhantomData, - } - } -} - -impl From for BoundedBytesString { - fn from(value: String) -> Self { - Self { - data: value.as_bytes().into(), - _phantom: PhantomData, - } - } -} diff --git a/precompiles/utils/src/solidity/codec/mod.rs b/precompiles/utils/src/solidity/codec/mod.rs deleted file mode 100644 index 1ebf6a32d1..0000000000 --- a/precompiles/utils/src/solidity/codec/mod.rs +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Solidity encoding following the -//! [Contract ABI Specification](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#abi) - -pub mod bytes; -pub mod native; - -#[cfg(any(feature = "codec-xcm", test))] -pub mod xcm; - -use crate::solidity::revert::{MayRevert, RevertReason}; -use core::{marker::PhantomData, ops::Range}; -use sp_core::{H256, U256}; -use sp_std::{convert::TryInto, vec, vec::Vec}; - -pub use alloc::string::String; -pub use bytes::{BoundedBytes, BoundedString, UnboundedBytes, UnboundedString}; -pub use native::{Address, BoundedVec}; - -// derive macro -pub use precompile_utils_macro_v2::Codec; - -/// Data that can be encoded/encoded followiong the Solidity ABI Specification. -pub trait Codec: Sized { - fn read(reader: &mut Reader) -> MayRevert; - fn write(writer: &mut Writer, value: Self); - fn has_static_size() -> bool; - fn signature() -> String; - fn is_explicit_tuple() -> bool { - false - } -} - -/// Encode the value into its Solidity ABI format. -/// If `T` is a tuple it is encoded as a Solidity tuple with dynamic-size offset. -fn encode(value: T) -> Vec { - Writer::new().write(value).build() -} - -/// Encode the value into its Solidity ABI format. -/// If `T` is a tuple every element is encoded without a prefixed offset. -/// It matches the encoding of Solidity function arguments and return value, or event data. -pub fn encode_arguments(value: T) -> Vec { - let output = encode(value); - if T::is_explicit_tuple() && !T::has_static_size() { - output[32..].to_vec() - } else { - output - } -} - -pub use self::{encode_arguments as encode_return_value, encode_arguments as encode_event_data}; - -/// Encode the value as the arguments of a Solidity function with given selector. -/// If `T` is a tuple each member represents an argument of the function. -pub fn encode_with_selector(selector: u32, value: T) -> Vec { - Writer::new_with_selector(selector) - .write_raw_bytes(&encode_arguments(value)) - .build() -} - -/// Decode the value from its Solidity ABI format. -/// If `T` is a tuple it is decoded as a Solidity tuple with dynamic-size offset. -fn decode(input: &[u8]) -> MayRevert { - Reader::new(input).read() -} - -/// Decode the value from its Solidity ABI format. -/// If `T` is a tuple every element is decoded without a prefixed offset. -/// It matches the encoding of Solidity function arguments and return value, or event data. -pub fn decode_arguments(input: &[u8]) -> MayRevert { - if T::is_explicit_tuple() && !T::has_static_size() { - let writer = Writer::new(); - let mut writer = writer.write(U256::from(32)); - writer.write_pointer(input.to_vec()); - let input = writer.build(); - decode(&input) - } else { - decode(input) - } -} - -pub use self::{decode_arguments as decode_return_value, decode_arguments as decode_event_data}; - -/// Extracts the selector from the start of the input, or returns `None` if the input is too short. -pub fn selector(input: &[u8]) -> Option { - input.get(0..4).map(|s| { - let mut buffer = [0u8; 4]; - buffer.copy_from_slice(s); - u32::from_be_bytes(buffer) - }) -} - -/// Wrapper around an EVM input slice. -#[derive(Clone, Copy, Debug)] -pub struct Reader<'inner> { - input: &'inner [u8], - cursor: usize, -} - -impl<'inner> Reader<'inner> { - /// Create a Reader. - pub fn new(input: &'inner [u8]) -> Self { - Self { input, cursor: 0 } - } - - /// Create a Reader while skipping an initial selector. - pub fn new_skip_selector(input: &'inner [u8]) -> MayRevert { - if input.len() < 4 { - return Err(RevertReason::read_out_of_bounds("selector").into()); - } - - Ok(Self::new(&input[4..])) - } - - /// Check the input has at least the correct amount of arguments before the end (32 bytes values). - pub fn expect_arguments(&self, args: usize) -> MayRevert { - if self.input.len() >= self.cursor + args * 32 { - Ok(()) - } else { - Err(RevertReason::ExpectedAtLeastNArguments(args).into()) - } - } - - /// Read data from the input. - pub fn read(&mut self) -> MayRevert { - T::read(self) - } - - /// Read raw bytes from the input. - /// Doesn't handle any alignment checks, prefer using `read` instead of possible. - /// Returns an error if trying to parse out of bounds. - pub fn read_raw_bytes(&mut self, len: usize) -> MayRevert<&[u8]> { - let range = self.move_cursor(len)?; - - let data = self - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds("raw bytes"))?; - - Ok(data) - } - - /// Reads a pointer, returning a reader targetting the pointed location. - pub fn read_pointer(&mut self) -> MayRevert { - let offset: usize = self - .read::() - .map_err(|_| RevertReason::read_out_of_bounds("pointer"))? - .try_into() - .map_err(|_| RevertReason::value_is_too_large("pointer"))?; - - if offset >= self.input.len() { - return Err(RevertReason::PointerToOutofBound.into()); - } - - Ok(Self { - input: &self.input[offset..], - cursor: 0, - }) - } - - /// Read remaining bytes - pub fn read_till_end(&mut self) -> MayRevert<&[u8]> { - let range = self.move_cursor(self.input.len() - self.cursor)?; - - let data = self - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds("raw bytes"))?; - - Ok(data) - } - - /// Move the reading cursor with provided length, and return a range from the previous cursor - /// location to the new one. - /// Checks cursor overflows. - fn move_cursor(&mut self, len: usize) -> MayRevert> { - let start = self.cursor; - let end = self - .cursor - .checked_add(len) - .ok_or(RevertReason::CursorOverflow)?; - - self.cursor = end; - - Ok(start..end) - } -} - -/// Help build an EVM input/output data. -/// -/// Functions takes `self` to allow chaining all calls like -/// `Writer::new().write(...).write(...).build()`. -/// While it could be more ergonomic to take &mut self, this would -/// prevent to have a `build` function that don't clone the output. -#[derive(Clone, Debug, Default)] -pub struct Writer { - pub(crate) data: Vec, - offset_data: Vec, - selector: Option, -} - -#[derive(Clone, Debug)] -struct OffsetChunk { - // Offset location in the container data. - offset_position: usize, - // Data pointed by the offset that must be inserted at the end of container data. - data: Vec, - // Inside of arrays, the offset is not from the start of array data (length), but from the start - // of the item. This shift allow to correct this. - offset_shift: usize, -} - -impl Writer { - /// Creates a new empty output builder (without selector). - pub fn new() -> Self { - Default::default() - } - - /// Creates a new empty output builder with provided selector. - /// Selector will only be appended before the data when calling - /// `build` to not mess with the offsets. - pub fn new_with_selector(selector: impl Into) -> Self { - Self { - data: vec![], - offset_data: vec![], - selector: Some(selector.into()), - } - } - - // Return the built data. - pub fn build(mut self) -> Vec { - Self::bake_offsets(&mut self.data, self.offset_data); - - if let Some(selector) = self.selector { - let mut output = selector.to_be_bytes().to_vec(); - output.append(&mut self.data); - output - } else { - self.data - } - } - - /// Add offseted data at the end of this writer's data, updating the offsets. - fn bake_offsets(output: &mut Vec, offsets: Vec) { - for mut offset_chunk in offsets { - let offset_position = offset_chunk.offset_position; - let offset_position_end = offset_position + 32; - - // The offset is the distance between the start of the data and the - // start of the pointed data (start of a struct, length of an array). - // Offsets in inner data are relative to the start of their respective "container". - // However in arrays the "container" is actually the item itself instead of the whole - // array, which is corrected by `offset_shift`. - let free_space_offset = output.len() - offset_chunk.offset_shift; - - // Override dummy offset to the offset it will be in the final output. - U256::from(free_space_offset) - .to_big_endian(&mut output[offset_position..offset_position_end]); - - // Append this data at the end of the current output. - output.append(&mut offset_chunk.data); - } - } - - /// Write arbitrary bytes. - /// Doesn't handle any alignement checks, prefer using `write` instead if possible. - fn write_raw_bytes(mut self, value: &[u8]) -> Self { - self.data.extend_from_slice(value); - self - } - - /// Write data of requested type. - pub fn write(mut self, value: T) -> Self { - T::write(&mut self, value); - self - } - - /// Writes a pointer to given data. - /// The data will be appended when calling `build`. - /// Initially write a dummy value as offset in this writer's data, which will be replaced by - /// the correct offset once the pointed data is appended. - /// - /// Takes `&mut self` since its goal is to be used inside `solidity::Codec` impl and not in chains. - pub fn write_pointer(&mut self, data: Vec) { - let offset_position = self.data.len(); - H256::write(self, H256::repeat_byte(0xff)); - - self.offset_data.push(OffsetChunk { - offset_position, - data, - offset_shift: 0, - }); - } -} - -/// Adapter to parse data as a first type then convert it to another one. -/// Useful for old precompiles in which Solidity arguments where set larger than -/// the needed Rust type. -#[derive(Clone, Copy, Debug)] -pub struct Convert { - inner: C, - _phantom: PhantomData

, -} - -impl From for Convert { - fn from(value: C) -> Self { - Self { - inner: value, - _phantom: PhantomData, - } - } -} - -impl Convert { - pub fn converted(self) -> C { - self.inner - } -} - -impl Codec for Convert -where - P: Codec + TryInto, - C: Codec + Into

, -{ - fn read(reader: &mut Reader) -> MayRevert { - let c = P::read(reader)? - .try_into() - .map_err(|_| RevertReason::value_is_too_large(C::signature()))?; - - Ok(Self { - inner: c, - _phantom: PhantomData, - }) - } - - fn write(writer: &mut Writer, value: Self) { - P::write(writer, value.inner.into()) - } - - fn has_static_size() -> bool { - P::has_static_size() - } - - fn signature() -> String { - P::signature() - } -} diff --git a/precompiles/utils/src/solidity/codec/native.rs b/precompiles/utils/src/solidity/codec/native.rs deleted file mode 100644 index e99f452ac3..0000000000 --- a/precompiles/utils/src/solidity/codec/native.rs +++ /dev/null @@ -1,383 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; -use crate::solidity::revert::InjectBacktrace; -use impl_trait_for_tuples::impl_for_tuples; -use sp_core::{ConstU32, Get, H160}; - -impl Codec for () { - fn read(_reader: &mut Reader) -> MayRevert { - Ok(()) - } - - fn write(_writer: &mut Writer, _value: Self) {} - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - String::from("()") - } -} - -#[impl_for_tuples(1, 18)] -impl Codec for Tuple { - fn has_static_size() -> bool { - for_tuples!(#( Tuple::has_static_size() )&*) - } - - fn read(reader: &mut Reader) -> MayRevert { - if Self::has_static_size() { - let mut index = 0; - Ok(for_tuples!( ( #( { - let elem = reader.read::().in_tuple(index)?; - index +=1; - elem - } ),* ) )) - } else { - let reader = &mut reader.read_pointer()?; - let mut index = 0; - Ok(for_tuples!( ( #( { - let elem = reader.read::().in_tuple(index)?; - index +=1; - elem - } ),* ) )) - } - } - - fn write(writer: &mut Writer, value: Self) { - if Self::has_static_size() { - for_tuples!( #( Tuple::write(writer, value.Tuple); )* ); - } else { - let mut inner_writer = Writer::new(); - for_tuples!( #( Tuple::write(&mut inner_writer, value.Tuple); )* ); - writer.write_pointer(inner_writer.build()); - } - } - - fn signature() -> String { - let mut subtypes = Vec::new(); - for_tuples!( #( subtypes.push(Tuple::signature()); )* ); - alloc::format!("({})", subtypes.join(",")) - } - - fn is_explicit_tuple() -> bool { - true - } -} - -impl Codec for H256 { - fn read(reader: &mut Reader) -> MayRevert { - let range = reader.move_cursor(32)?; - - let data = reader - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds("bytes32"))?; - - Ok(H256::from_slice(data)) - } - - fn write(writer: &mut Writer, value: Self) { - writer.data.extend_from_slice(value.as_bytes()); - } - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - String::from("bytes32") - } -} - -/// The `address` type of Solidity. -/// H160 could represent 2 types of data (bytes20 and address) that are not encoded the same way. -/// To avoid issues writing H160 is thus not supported. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct Address(pub H160); - -impl From for Address { - fn from(a: H160) -> Address { - Address(a) - } -} - -impl From

for H160 { - fn from(a: Address) -> H160 { - a.0 - } -} - -impl Address { - pub fn as_u64(&self) -> Option { - let _u64 = self.0.to_low_u64_be(); - if self.0 == H160::from_low_u64_be(_u64) { - Some(_u64) - } else { - None - } - } -} - -impl Codec for Address { - fn read(reader: &mut Reader) -> MayRevert { - let range = reader.move_cursor(32)?; - - let data = reader - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds("address"))?; - - Ok(H160::from_slice(&data[12..32]).into()) - } - - fn write(writer: &mut Writer, value: Self) { - H256::write(writer, value.0.into()); - } - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - String::from("address") - } -} - -impl Codec for U256 { - fn read(reader: &mut Reader) -> MayRevert { - let range = reader.move_cursor(32)?; - - let data = reader - .input - .get(range) - .ok_or_else(|| RevertReason::read_out_of_bounds("uint256"))?; - - Ok(U256::from_big_endian(data)) - } - - fn write(writer: &mut Writer, value: Self) { - let mut buffer = [0u8; 32]; - value.to_big_endian(&mut buffer); - writer.data.extend_from_slice(&buffer); - } - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - String::from("uint256") - } -} - -macro_rules! impl_evmdata_for_uints { - ($($uint:ty, )*) => { - $( - impl Codec for $uint { - fn read(reader: &mut Reader) -> MayRevert { - let value256: U256 = reader.read() - .map_err(|_| RevertReason::read_out_of_bounds( - Self::signature() - ))?; - - value256 - .try_into() - .map_err(|_| RevertReason::value_is_too_large( - Self::signature() - ).into()) - } - - fn write(writer: &mut Writer, value: Self) { - U256::write(writer, value.into()); - } - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - alloc::format!("uint{}", core::mem::size_of::() * 8) - } - } - )* - }; -} - -impl_evmdata_for_uints!(u8, u16, u32, u64, u128,); - -impl Codec for bool { - fn read(reader: &mut Reader) -> MayRevert { - let h256 = H256::read(reader).map_err(|_| RevertReason::read_out_of_bounds("bool"))?; - - Ok(!h256.is_zero()) - } - - fn write(writer: &mut Writer, value: Self) { - let mut buffer = [0u8; 32]; - if value { - buffer[31] = 1; - } - - writer.data.extend_from_slice(&buffer); - } - - fn has_static_size() -> bool { - true - } - - fn signature() -> String { - String::from("bool") - } -} - -type ConstU32Max = ConstU32<{ u32::MAX }>; - -impl Codec for Vec { - fn read(reader: &mut Reader) -> MayRevert { - BoundedVec::::read(reader).map(|x| x.into()) - } - - fn write(writer: &mut Writer, value: Self) { - BoundedVec::::write( - writer, - BoundedVec { - inner: value, - _phantom: PhantomData, - }, - ) - } - - fn has_static_size() -> bool { - false - } - - fn signature() -> String { - alloc::format!("{}[]", T::signature()) - } -} - -/// Wrapper around a Vec that provides a max length bound on read. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BoundedVec { - inner: Vec, - _phantom: PhantomData, -} - -impl> Codec for BoundedVec { - fn read(reader: &mut Reader) -> MayRevert { - let mut inner_reader = reader.read_pointer()?; - - let array_size: usize = inner_reader - .read::() - .map_err(|_| RevertReason::read_out_of_bounds("length"))? - .try_into() - .map_err(|_| RevertReason::value_is_too_large("length"))?; - - if array_size > S::get() as usize { - return Err(RevertReason::value_is_too_large("length").into()); - } - - let mut array = vec![]; - - let mut item_reader = Reader { - input: inner_reader - .input - .get(32..) - .ok_or_else(|| RevertReason::read_out_of_bounds("array content"))?, - cursor: 0, - }; - - for i in 0..array_size { - array.push(item_reader.read().in_array(i)?); - } - - Ok(BoundedVec { - inner: array, - _phantom: PhantomData, - }) - } - - fn write(writer: &mut Writer, value: Self) { - let value: Vec<_> = value.into(); - let mut inner_writer = Writer::new().write(U256::from(value.len())); - - for inner in value { - // Any offset in items are relative to the start of the item instead of the - // start of the array. However if there is offseted data it must but appended after - // all items (offsets) are written. We thus need to rely on `compute_offsets` to do - // that, and must store a "shift" to correct the offsets. - let shift = inner_writer.data.len(); - let item_writer = Writer::new().write(inner); - - inner_writer = inner_writer.write_raw_bytes(&item_writer.data); - for mut offset_datum in item_writer.offset_data { - offset_datum.offset_shift += 32; - offset_datum.offset_position += shift; - inner_writer.offset_data.push(offset_datum); - } - } - - writer.write_pointer(inner_writer.build()); - } - - fn has_static_size() -> bool { - false - } - - fn signature() -> String { - alloc::format!("{}[]", T::signature()) - } -} - -impl From> for BoundedVec { - fn from(value: Vec) -> Self { - BoundedVec { - inner: value, - _phantom: PhantomData, - } - } -} - -impl From<&[T]> for BoundedVec { - fn from(value: &[T]) -> Self { - BoundedVec { - inner: value.to_vec(), - _phantom: PhantomData, - } - } -} - -impl From<[T; N]> for BoundedVec { - fn from(value: [T; N]) -> Self { - BoundedVec { - inner: value.to_vec(), - _phantom: PhantomData, - } - } -} - -impl From> for Vec { - fn from(value: BoundedVec) -> Self { - value.inner - } -} diff --git a/precompiles/utils/src/solidity/codec/xcm.rs b/precompiles/utils/src/solidity/codec/xcm.rs deleted file mode 100644 index fdefed4dc2..0000000000 --- a/precompiles/utils/src/solidity/codec/xcm.rs +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright 2019-2022 PureStake Inc. -// This file is part of Moonbeam. - -// Moonbeam is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Moonbeam is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Moonbeam. If not, see . - -//! Encoding of XCM types for solidity - -use { - crate::solidity::{ - codec::{bytes::*, Codec, Reader, Writer}, - revert::{BacktraceExt, InjectBacktrace, MayRevert, RevertReason}, - }, - alloc::string::String, - frame_support::{ensure, traits::ConstU32}, - sp_core::H256, - sp_std::vec::Vec, - xcm::latest::{Junction, Junctions, Location, NetworkId}, -}; - -pub const JUNCTION_SIZE_LIMIT: u32 = 2u32.pow(16); - -// Function to convert network id to bytes -// We don't implement solidity::Codec here as these bytes will be appended only -// to certain Junction variants -// Each NetworkId variant is represented as bytes -// The first byte represents the enum variant to be used. -// - Indexes 0,2,3 represent XCM V2 variants -// - Index 1 changes name in V3 (`ByGenesis`), but is compatible with V2 `Named` -// - Indexes 4~10 represent new XCM V3 variants -// The rest of the bytes (if any), represent the additional data that such enum variant requires -// In such a case, since NetworkIds will be appended at the end, we will read the buffer until the -// end to recover the name - -pub(crate) fn network_id_to_bytes(network_id: Option) -> Vec { - let mut encoded: Vec = Vec::new(); - match network_id.clone() { - None => { - encoded.push(0u8); - encoded - } - Some(NetworkId::ByGenesis(id)) => { - encoded.push(1u8); - encoded.append(&mut id.into()); - encoded - } - Some(NetworkId::Polkadot) => { - encoded.push(2u8); - encoded.push(2u8); - encoded - } - Some(NetworkId::Kusama) => { - encoded.push(3u8); - encoded.push(3u8); - encoded - } - Some(NetworkId::ByFork { - block_number, - block_hash, - }) => { - encoded.push(4u8); - encoded.push(1u8); - encoded.append(&mut block_number.to_be_bytes().into()); - encoded.append(&mut block_hash.into()); - encoded - } - Some(NetworkId::Westend) => { - encoded.push(5u8); - encoded.push(4u8); - encoded - } - Some(NetworkId::Rococo) => { - encoded.push(6u8); - encoded.push(5u8); - encoded - } - Some(NetworkId::Wococo) => { - encoded.push(7u8); - encoded.push(6u8); - encoded - } - Some(NetworkId::Ethereum { chain_id }) => { - encoded.push(8u8); - encoded.push(7u8); - encoded.append(&mut chain_id.to_be_bytes().into()); - encoded - } - Some(NetworkId::BitcoinCore) => { - encoded.push(9u8); - encoded.push(8u8); - encoded - } - Some(NetworkId::BitcoinCash) => { - encoded.push(10u8); - encoded.push(9u8); - encoded - } - Some(NetworkId::PolkadotBulletin) => { - encoded.push(11u8); - encoded.push(10u8); - encoded - } - } -} - -// Function to convert bytes to networkId -pub(crate) fn network_id_from_bytes(encoded_bytes: Vec) -> MayRevert> { - ensure!( - encoded_bytes.len() > 0, - RevertReason::custom("Junctions cannot be empty") - ); - let mut encoded_network_id = Reader::new(&encoded_bytes); - - let network_selector = encoded_network_id - .read_raw_bytes(1) - .map_err(|_| RevertReason::read_out_of_bounds("network selector (1 byte)"))?; - - match network_selector[0] { - 0 => Ok(None), - 1 => Ok(Some(NetworkId::ByGenesis( - encoded_network_id - .read_till_end() - .in_field("genesis")? - .to_vec() - .try_into() - .map_err(|_| { - RevertReason::value_is_too_large("network by genesis").in_field("genesis") - })?, - ))), - 2 => Ok(Some(NetworkId::Polkadot)), - 3 => Ok(Some(NetworkId::Kusama)), - 4 => { - let mut block_number: [u8; 8] = Default::default(); - block_number.copy_from_slice(&encoded_network_id.read_raw_bytes(8)?); - - let mut block_hash: [u8; 32] = Default::default(); - block_hash.copy_from_slice(&encoded_network_id.read_raw_bytes(32)?); - Ok(Some(NetworkId::ByFork { - block_number: u64::from_be_bytes(block_number), - block_hash, - })) - } - 5 => Ok(Some(NetworkId::Westend)), - 6 => Ok(Some(NetworkId::Rococo)), - 7 => Ok(Some(NetworkId::Wococo)), - 8 => { - let mut chain_id: [u8; 8] = Default::default(); - chain_id.copy_from_slice(&encoded_network_id.read_raw_bytes(8)?); - Ok(Some(NetworkId::Ethereum { - chain_id: u64::from_be_bytes(chain_id), - })) - } - 9 => Ok(Some(NetworkId::BitcoinCore)), - 10 => Ok(Some(NetworkId::BitcoinCash)), - _ => Err(RevertReason::custom("Non-valid Network Id").into()), - } -} - -impl Codec for Junction { - fn read(reader: &mut Reader) -> MayRevert { - let junction = reader.read::>>()?; - let junction_bytes: Vec<_> = junction.into(); - - ensure!( - junction_bytes.len() > 0, - RevertReason::custom("Junctions cannot be empty") - ); - - // For simplicity we use an EvmReader here - let mut encoded_junction = Reader::new(&junction_bytes); - - // We take the first byte - let enum_selector = encoded_junction - .read_raw_bytes(1) - .map_err(|_| RevertReason::read_out_of_bounds("junction variant"))?; - - // The firs byte selects the enum variant - match enum_selector[0] { - 0 => { - // In the case of Junction::Parachain, we need 4 additional bytes - let mut data: [u8; 4] = Default::default(); - data.copy_from_slice(&encoded_junction.read_raw_bytes(4)?); - let para_id = u32::from_be_bytes(data); - Ok(Junction::Parachain(para_id)) - } - 1 => { - // In the case of Junction::AccountId32, we need 32 additional bytes plus NetworkId - let mut account: [u8; 32] = Default::default(); - account.copy_from_slice(&encoded_junction.read_raw_bytes(32)?); - - let network = encoded_junction.read_till_end()?.to_vec(); - Ok(Junction::AccountId32 { - network: network_id_from_bytes(network)?, - id: account, - }) - } - 2 => { - // In the case of Junction::AccountIndex64, we need 8 additional bytes plus NetworkId - let mut index: [u8; 8] = Default::default(); - index.copy_from_slice(&encoded_junction.read_raw_bytes(8)?); - // Now we read the network - let network = encoded_junction.read_till_end()?.to_vec(); - Ok(Junction::AccountIndex64 { - network: network_id_from_bytes(network)?, - index: u64::from_be_bytes(index), - }) - } - 3 => { - // In the case of Junction::AccountKey20, we need 20 additional bytes plus NetworkId - let mut account: [u8; 20] = Default::default(); - account.copy_from_slice(&encoded_junction.read_raw_bytes(20)?); - - let network = encoded_junction.read_till_end()?.to_vec(); - Ok(Junction::AccountKey20 { - network: network_id_from_bytes(network)?, - key: account, - }) - } - 4 => Ok(Junction::PalletInstance( - encoded_junction.read_raw_bytes(1)?[0], - )), - 5 => { - // In the case of Junction::GeneralIndex, we need 16 additional bytes - let mut general_index: [u8; 16] = Default::default(); - general_index.copy_from_slice(&encoded_junction.read_raw_bytes(16)?); - Ok(Junction::GeneralIndex(u128::from_be_bytes(general_index))) - } - 6 => { - let length = encoded_junction - .read_raw_bytes(1) - .map_err(|_| RevertReason::read_out_of_bounds("General Key length"))?[0]; - - let data = encoded_junction.read::().in_field("data")?.into(); - - Ok(Junction::GeneralKey { length, data }) - } - 7 => Ok(Junction::OnlyChild), - 8 => Err(RevertReason::custom("Junction::Plurality not supported yet").into()), - 9 => { - let network = encoded_junction.read_till_end()?.to_vec(); - if let Some(network_id) = network_id_from_bytes(network)? { - Ok(Junction::GlobalConsensus(network_id)) - } else { - Err(RevertReason::custom("Unknown NetworkId").into()) - } - } - _ => Err(RevertReason::custom("Unknown Junction variant").into()), - } - } - - fn write(writer: &mut Writer, value: Self) { - let mut encoded: Vec = Vec::new(); - let encoded_bytes: UnboundedBytes = match value { - Junction::Parachain(para_id) => { - encoded.push(0u8); - encoded.append(&mut para_id.to_be_bytes().to_vec()); - encoded.as_slice().into() - } - Junction::AccountId32 { network, id } => { - encoded.push(1u8); - encoded.append(&mut id.to_vec()); - encoded.append(&mut network_id_to_bytes(network)); - encoded.as_slice().into() - } - Junction::AccountIndex64 { network, index } => { - encoded.push(2u8); - encoded.append(&mut index.to_be_bytes().to_vec()); - encoded.append(&mut network_id_to_bytes(network)); - encoded.as_slice().into() - } - Junction::AccountKey20 { network, key } => { - encoded.push(3u8); - encoded.append(&mut key.to_vec()); - encoded.append(&mut network_id_to_bytes(network)); - encoded.as_slice().into() - } - Junction::PalletInstance(intance) => { - encoded.push(4u8); - encoded.append(&mut intance.to_be_bytes().to_vec()); - encoded.as_slice().into() - } - Junction::GeneralIndex(id) => { - encoded.push(5u8); - encoded.append(&mut id.to_be_bytes().to_vec()); - encoded.as_slice().into() - } - Junction::GeneralKey { length, data } => { - encoded.push(6u8); - encoded.push(length); - encoded.append(&mut data.into()); - encoded.as_slice().into() - } - Junction::OnlyChild => { - encoded.push(7u8); - encoded.as_slice().into() - } - Junction::GlobalConsensus(network_id) => { - encoded.push(9u8); - encoded.append(&mut network_id_to_bytes(Some(network_id))); - encoded.as_slice().into() - } - // TODO: The only missing item here is Junciton::Plurality. This is a complex encoded - // type that we need to evaluate how to support - _ => unreachable!("Junction::Plurality not supported yet"), - }; - Codec::write(writer, encoded_bytes); - } - - fn has_static_size() -> bool { - false - } - - fn signature() -> String { - UnboundedBytes::signature() - } -} - -impl Codec for Junctions { - fn read(reader: &mut Reader) -> MayRevert { - let junctions_bytes: Vec = reader.read()?; - let mut junctions = Junctions::Here; - for item in junctions_bytes { - junctions - .push(item) - .map_err(|_| RevertReason::custom("overflow when reading junctions"))?; - } - - Ok(junctions) - } - - fn write(writer: &mut Writer, value: Self) { - let encoded: Vec = value.iter().map(|junction| junction.clone()).collect(); - Codec::write(writer, encoded); - } - - fn has_static_size() -> bool { - false - } - - fn signature() -> String { - Vec::::signature() - } -} - -// Cannot used derive macro since it is a foreign struct. -impl Codec for Location { - fn read(reader: &mut Reader) -> MayRevert { - let (parents, interior) = reader - .read() - .map_in_tuple_to_field(&["parents", "interior"])?; - Ok(Location { parents, interior }) - } - - fn write(writer: &mut Writer, value: Self) { - Codec::write(writer, (value.parents, value.interior)); - } - - fn has_static_size() -> bool { - <(u8, Junctions)>::has_static_size() - } - - fn signature() -> String { - <(u8, Junctions)>::signature() - } -} diff --git a/precompiles/utils/src/solidity/mod.rs b/precompiles/utils/src/solidity/mod.rs deleted file mode 100644 index fa45c50ff9..0000000000 --- a/precompiles/utils/src/solidity/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Provides utilities for compatibility with Solidity tooling. - -pub mod codec; -pub mod modifier; -pub mod revert; - -pub use codec::{ - decode_arguments, decode_event_data, decode_return_value, encode_arguments, encode_event_data, - encode_return_value, encode_with_selector, Codec, -}; diff --git a/precompiles/utils/src/solidity/modifier.rs b/precompiles/utils/src/solidity/modifier.rs deleted file mode 100644 index 0bae1bf984..0000000000 --- a/precompiles/utils/src/solidity/modifier.rs +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Provide checks related to function modifiers (view/payable). - -use crate::solidity::revert::{MayRevert, RevertReason}; -use fp_evm::Context; -use sp_core::U256; - -/// Represents modifiers a Solidity function can be annotated with. -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum FunctionModifier { - /// Function that doesn't modify the state. - View, - /// Function that modifies the state but refuse receiving funds. - /// Correspond to a Solidity function with no modifiers. - NonPayable, - /// Function that modifies the state and accept funds. - Payable, -} - -/// Check that a function call is compatible with the context it is -/// called into. -pub fn check_function_modifier( - context: &Context, - is_static: bool, - modifier: FunctionModifier, -) -> MayRevert { - if is_static && modifier != FunctionModifier::View { - return Err( - RevertReason::custom("Can't call non-static function in static context").into(), - ); - } - - if modifier != FunctionModifier::Payable && context.apparent_value > U256::zero() { - return Err(RevertReason::custom("Function is not payable").into()); - } - - Ok(()) -} diff --git a/precompiles/utils/src/solidity/revert.rs b/precompiles/utils/src/solidity/revert.rs deleted file mode 100644 index 8269a83706..0000000000 --- a/precompiles/utils/src/solidity/revert.rs +++ /dev/null @@ -1,385 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Utilities to work with revert messages with support for backtraces and -//! consistent formatting. - -use crate::solidity::{self, codec::bytes::UnboundedBytes}; -use alloc::string::{String, ToString}; -use fp_evm::{ExitRevert, PrecompileFailure}; -use sp_std::vec::Vec; - -/// Represent the result of a computation that can revert. -pub type MayRevert = Result; - -/// Generate an encoded revert from a simple String. -/// Returns a `PrecompileFailure` that fits in an `EvmResult::Err`. -pub fn revert(msg: impl Into) -> PrecompileFailure { - RevertReason::custom(msg).into() -} - -/// Generate an encoded revert from a simple String. -/// Returns a `Vec` in case `PrecompileFailure` is too high level. -pub fn revert_as_bytes(msg: impl Into) -> Vec { - Revert::new(RevertReason::custom(msg)).to_encoded_bytes() -} - -/// Generic error to build abi-encoded revert output. -/// See: https://docs.soliditylang.org/en/latest/control-structures.html?highlight=revert#revert -pub const ERROR_SELECTOR: u32 = 0x08c379a0; - -#[derive(Clone, PartialEq, Eq)] -enum BacktracePart { - Field(String), - Tuple(usize), - Array(usize), -} - -/// Backtrace of an revert. -/// Built depth-first. -/// Implement `Display` to render the backtrace as a string. -#[derive(Default, PartialEq, Eq)] -pub struct Backtrace(Vec); - -impl Backtrace { - /// Create a new empty backtrace. - pub fn new() -> Self { - Self(Vec::new()) - } - - /// Check if the backtrace is empty. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl core::fmt::Display for Backtrace { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - for (i, part) in self.0.iter().rev().enumerate() { - match (i, part) { - (0, BacktracePart::Field(field)) => write!(f, "{field}")?, - (_, BacktracePart::Field(field)) => write!(f, ".{field}")?, - (_, BacktracePart::Tuple(index)) => write!(f, ".{index}")?, - (_, BacktracePart::Array(index)) => write!(f, "[{index}]")?, - } - } - Ok(()) - } -} - -/// Possible revert reasons. -#[non_exhaustive] -#[derive(PartialEq, Eq)] -pub enum RevertReason { - /// A custom revert reason if other variants are not appropriate. - Custom(String), - /// Tried to read data out of bounds. - ReadOutOfBounds { - /// What was being read? - what: String, - }, - /// An unknown selector has been provided. - UnknownSelector, - /// A value is too large to fit in the wanted type. - /// For security reasons integers are always parsed as `uint256` then - /// casted to the wanted type. If the value overflows this type then this - /// revert is used. - ValueIsTooLarge { - /// What was being read? - what: String, - }, - /// A pointer (used for structs and arrays) points out of bounds. - PointerToOutofBound, - /// The reading cursor overflowed. - /// This should realistically never happen as it would require an input - /// of length larger than 2^64, which would cost too much to be included - /// in a block. - CursorOverflow, - /// Used by a check that the input contains at least N static arguments. - /// Often use to return early if the input is too short. - ExpectedAtLeastNArguments(usize), -} - -impl RevertReason { - /// Create a `RevertReason::Custom` from anything that can be converted to a `String`. - /// Argument is the custom revert message. - pub fn custom(s: impl Into) -> Self { - RevertReason::Custom(s.into()) - } - - /// Create a `RevertReason::ReadOutOfBounds` from anything that can be converted to a `String`. - /// Argument names what was expected to be read. - pub fn read_out_of_bounds(what: impl Into) -> Self { - RevertReason::ReadOutOfBounds { what: what.into() } - } - - /// Create a `RevertReason::ValueIsTooLarge` from anything that can be converted to a `String`. - /// Argument names what was expected to be read. - pub fn value_is_too_large(what: impl Into) -> Self { - RevertReason::ValueIsTooLarge { what: what.into() } - } -} - -impl core::fmt::Display for RevertReason { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - match self { - RevertReason::Custom(s) => write!(f, "{s}"), - RevertReason::ReadOutOfBounds { what } => { - write!(f, "Tried to read {what} out of bounds") - } - RevertReason::UnknownSelector => write!(f, "Unknown selector"), - RevertReason::ValueIsTooLarge { what } => write!(f, "Value is too large for {what}"), - RevertReason::PointerToOutofBound => write!(f, "Pointer points to out of bound"), - RevertReason::CursorOverflow => write!(f, "Reading cursor overflowed"), - RevertReason::ExpectedAtLeastNArguments(n) => { - write!(f, "Expected at least {n} arguments") - } - } - } -} - -/// An revert returned by various functions in precompile-utils. -/// Allows to dynamically construct the backtrace (backtrace) of the revert -/// and manage it in a typed way. -/// Can be transformed into a `PrecompileFailure::Revert` and `String`, and -/// implement `Display` and `Debug`. -#[derive(PartialEq, Eq)] -pub struct Revert { - reason: RevertReason, - backtrace: Backtrace, -} - -impl Revert { - /// Create a new `Revert` with a `RevertReason` and - /// an empty backtrace. - pub fn new(reason: RevertReason) -> Self { - Self { - reason, - backtrace: Backtrace::new(), - } - } - - /// For all `RevertReason` variants that have a `what` field, change its value. - /// Otherwise do nothing. - /// It is useful when writing custom types `solidity::Codec` implementations using - /// simpler types. - pub fn change_what(mut self, what: impl Into) -> Self { - let what = what.into(); - - self.reason = match self.reason { - RevertReason::ReadOutOfBounds { .. } => RevertReason::ReadOutOfBounds { what }, - RevertReason::ValueIsTooLarge { .. } => RevertReason::ValueIsTooLarge { what }, - other => other, - }; - - self - } - - /// Transforms the revert into its bytes representation (from a String). - pub fn to_encoded_bytes(self) -> Vec { - let bytes: Vec = self.into(); - solidity::encode_with_selector(ERROR_SELECTOR, UnboundedBytes::from(bytes)) - } -} - -impl From for Revert { - fn from(a: RevertReason) -> Revert { - Revert::new(a) - } -} - -impl core::fmt::Display for Revert { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - if !self.backtrace.is_empty() { - write!(f, "{}: ", self.backtrace)?; - } - - write!(f, "{}", self.reason) - } -} - -impl core::fmt::Debug for Revert { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}", self) - } -} - -impl From for Vec { - fn from(val: Revert) -> Self { - val.to_string().into() - } -} - -/// Allows to inject backtrace data. -pub trait InjectBacktrace { - /// Output type of the injection. - /// Should be a type that can hold a backtrace. - type Output; - - /// Occurs in a field. - fn in_field(self, field: impl Into) -> Self::Output; - - /// Occurs in a tuple. - fn in_tuple(self, index: usize) -> Self::Output; - - /// Occurs in an array at provided index. - fn in_array(self, index: usize) -> Self::Output; -} - -/// Additional function for everything having a Backtrace. -pub trait BacktraceExt { - /// Map last tuple entry into a field. - /// Does nothing if last entry is not a tuple. - /// As in Solidity structs are equivalent to tuples and are tricky to parse correctly, - /// it allows to parse any struct as a tuple (with the correct implementation in this crate) and - /// then map tuple indices to struct fields. - fn map_in_tuple_to_field(self, fields: &[&'static str]) -> Self; -} - -/// Additional functions for Revert and MayRevert. -pub trait RevertExt { - /// Map the reason while keeping the same backtrace. - fn map_reason(self, f: impl FnOnce(RevertReason) -> RevertReason) -> Self; -} - -impl InjectBacktrace for RevertReason { - // `RevertReason` cannot hold a backtrace, thus it wraps - // it into a `Revert`. - type Output = Revert; - - fn in_field(self, field: impl Into) -> Revert { - Revert::new(self).in_field(field) - } - - fn in_array(self, index: usize) -> Revert { - Revert::new(self).in_array(index) - } - - fn in_tuple(self, index: usize) -> Revert { - Revert::new(self).in_tuple(index) - } -} - -impl InjectBacktrace for Backtrace { - type Output = Self; - - fn in_field(mut self, field: impl Into) -> Self { - self.0.push(BacktracePart::Field(field.into())); - self - } - - fn in_array(mut self, index: usize) -> Self { - self.0.push(BacktracePart::Array(index)); - self - } - - fn in_tuple(mut self, index: usize) -> Self { - self.0.push(BacktracePart::Tuple(index)); - self - } -} - -impl BacktraceExt for Backtrace { - fn map_in_tuple_to_field(mut self, fields: &[&'static str]) -> Self { - if let Some(entry) = self.0.last_mut() { - if let BacktracePart::Tuple(index) = *entry { - if let Some(field) = fields.get(index) { - *entry = BacktracePart::Field(field.to_string()) - } - } - } - self - } -} - -impl InjectBacktrace for Revert { - type Output = Self; - - fn in_field(mut self, field: impl Into) -> Self { - self.backtrace = self.backtrace.in_field(field); - self - } - - fn in_array(mut self, index: usize) -> Self { - self.backtrace = self.backtrace.in_array(index); - self - } - - fn in_tuple(mut self, index: usize) -> Self { - self.backtrace = self.backtrace.in_tuple(index); - self - } -} - -impl RevertExt for Revert { - fn map_reason(mut self, f: impl FnOnce(RevertReason) -> RevertReason) -> Self { - self.reason = f(self.reason); - self - } -} - -impl BacktraceExt for Revert { - fn map_in_tuple_to_field(mut self, fields: &[&'static str]) -> Self { - self.backtrace = self.backtrace.map_in_tuple_to_field(fields); - self - } -} - -impl InjectBacktrace for MayRevert { - type Output = Self; - - fn in_field(self, field: impl Into) -> Self { - self.map_err(|e| e.in_field(field)) - } - - fn in_array(self, index: usize) -> Self { - self.map_err(|e| e.in_array(index)) - } - - fn in_tuple(self, index: usize) -> Self { - self.map_err(|e| e.in_tuple(index)) - } -} - -impl RevertExt for MayRevert { - fn map_reason(self, f: impl FnOnce(RevertReason) -> RevertReason) -> Self { - self.map_err(|e| e.map_reason(f)) - } -} - -impl BacktraceExt for MayRevert { - fn map_in_tuple_to_field(self, fields: &[&'static str]) -> Self { - self.map_err(|e| e.map_in_tuple_to_field(fields)) - } -} - -impl From for PrecompileFailure { - fn from(err: Revert) -> Self { - PrecompileFailure::Revert { - exit_status: ExitRevert::Reverted, - output: err.to_encoded_bytes(), - } - } -} - -impl From for PrecompileFailure { - fn from(err: RevertReason) -> Self { - Revert::new(err).into() - } -} diff --git a/precompiles/utils/src/substrate.rs b/precompiles/utils/src/substrate.rs deleted file mode 100644 index bc5eda2c34..0000000000 --- a/precompiles/utils/src/substrate.rs +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Utils related to Substrate features: -//! - Substrate call dispatch. -//! - Substrate DB read and write costs - -use core::marker::PhantomData; - -// Substrate -use frame_support::{ - dispatch::{GetDispatchInfo, PostDispatchInfo}, - traits::Get, - weights::Weight, -}; -use sp_runtime::{traits::Dispatchable, DispatchError}; -// Frontier -use fp_evm::{ExitError, PrecompileFailure, PrecompileHandle}; -use pallet_evm::GasWeightMapping; - -use crate::{evm::handle::using_precompile_handle, solidity::revert::revert}; - -#[derive(Debug)] -pub enum TryDispatchError { - Evm(ExitError), - Substrate(DispatchError), -} - -impl From for PrecompileFailure { - fn from(f: TryDispatchError) -> PrecompileFailure { - match f { - TryDispatchError::Evm(e) => PrecompileFailure::Error { exit_status: e }, - TryDispatchError::Substrate(e) => { - revert(alloc::format!("Dispatched call failed with error: {e:?}")) - } - } - } -} - -/// Helper functions requiring a Substrate runtime. -/// This runtime must of course implement `pallet_evm::Config`. -#[derive(Clone, Copy, Debug)] -pub struct RuntimeHelper(PhantomData); - -impl RuntimeHelper -where - Runtime: pallet_evm::Config, - Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, -{ - #[inline(always)] - pub fn record_weight_v2_cost( - handle: &mut impl PrecompileHandle, - weight: Weight, - ) -> Result<(), ExitError> { - // Make sure there is enough gas. - let remaining_gas = handle.remaining_gas(); - let required_gas = Runtime::GasWeightMapping::weight_to_gas(weight); - if required_gas > remaining_gas { - return Err(ExitError::OutOfGas); - } - - // Make sure there is enough remaining weight - // TODO: record ref time when precompile will be benchmarked - handle.record_external_cost(None, Some(weight.proof_size()), None) - } - - #[inline(always)] - pub fn refund_weight_v2_cost( - handle: &mut impl PrecompileHandle, - weight: Weight, - maybe_actual_weight: Option, - ) -> Result { - // Refund weights and compute used weight them record used gas - // TODO: refund ref time when precompile will be benchmarked - let used_weight = if let Some(actual_weight) = maybe_actual_weight { - let refund_weight = weight.checked_sub(&actual_weight).unwrap_or_default(); - handle.refund_external_cost(None, Some(refund_weight.proof_size())); - actual_weight - } else { - weight - }; - let used_gas = Runtime::GasWeightMapping::weight_to_gas(used_weight); - handle.record_cost(used_gas)?; - Ok(used_gas) - } - - /// Try to dispatch a Substrate call. - /// Return an error if there are not enough gas, or if the call fails. - /// If successful returns the used gas using the Runtime GasWeightMapping. - pub fn try_dispatch( - handle: &mut impl PrecompileHandle, - origin: ::RuntimeOrigin, - call: Call, - ) -> Result - where - Runtime::RuntimeCall: From, - { - let call = Runtime::RuntimeCall::from(call); - let dispatch_info = call.get_dispatch_info(); - - Self::record_weight_v2_cost(handle, dispatch_info.weight).map_err(TryDispatchError::Evm)?; - - // Dispatch call. - // It may be possible to not record gas cost if the call returns Pays::No. - // However while Substrate handle checking weight while not making the sender pay for it, - // the EVM doesn't. It seems this safer to always record the costs to avoid unmetered - // computations. - let post_dispatch_info = using_precompile_handle(handle, || call.dispatch(origin)) - .map_err(|e| TryDispatchError::Substrate(e.error))?; - - Self::refund_weight_v2_cost( - handle, - dispatch_info.weight, - post_dispatch_info.actual_weight, - ) - .map_err(TryDispatchError::Evm)?; - - Ok(post_dispatch_info) - } -} - -impl RuntimeHelper -where - Runtime: pallet_evm::Config, -{ - /// Cost of a Substrate DB write in gas. - pub fn db_write_gas_cost() -> u64 { - ::GasWeightMapping::weight_to_gas( - ::DbWeight::get().writes(1), - ) - } - - /// Cost of a Substrate DB read in gas. - pub fn db_read_gas_cost() -> u64 { - ::GasWeightMapping::weight_to_gas( - ::DbWeight::get().reads(1), - ) - } -} diff --git a/precompiles/utils/src/testing/account.rs b/precompiles/utils/src/testing/account.rs deleted file mode 100644 index ec9bcf964a..0000000000 --- a/precompiles/utils/src/testing/account.rs +++ /dev/null @@ -1,188 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use pallet_evm::AddressMapping; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_core::{Decode, Encode, MaxEncodedLen, H160, H256}; - -#[derive( - Eq, - PartialEq, - Ord, - PartialOrd, - Clone, - Encode, - Decode, - Debug, - MaxEncodedLen, - TypeInfo, - Serialize, - Deserialize, - derive_more::Display, -)] -pub struct MockAccount(pub H160); - -impl MockAccount { - pub fn from_u64(v: u64) -> Self { - H160::from_low_u64_be(v).into() - } - - pub fn zero() -> Self { - H160::zero().into() - } - - pub fn has_prefix(&self, prefix: &[u8]) -> bool { - &self.0[0..4] == prefix - } - - pub fn has_prefix_u32(&self, prefix: u32) -> bool { - self.0[0..4] == prefix.to_be_bytes() - } - - pub fn without_prefix(&self) -> u128 { - u128::from_be_bytes(<[u8; 16]>::try_from(&self.0[4..20]).expect("slice have len 16")) - } -} - -impl From for H160 { - fn from(account: MockAccount) -> H160 { - account.0 - } -} - -impl From for [u8; 20] { - fn from(account: MockAccount) -> [u8; 20] { - let x: H160 = account.into(); - x.into() - } -} - -impl From for H256 { - fn from(x: MockAccount) -> H256 { - let x: H160 = x.into(); - x.into() - } -} - -impl From for MockAccount { - fn from(address: H160) -> MockAccount { - MockAccount(address) - } -} - -impl From<[u8; 20]> for MockAccount { - fn from(address: [u8; 20]) -> MockAccount { - let x: H160 = address.into(); - MockAccount(x) - } -} - -impl AddressMapping for MockAccount { - fn into_account_id(address: H160) -> MockAccount { - address.into() - } -} - -impl sp_runtime::traits::Convert for MockAccount { - fn convert(address: H160) -> MockAccount { - address.into() - } -} - -#[macro_export] -macro_rules! mock_account { - ($name:ident, $convert:expr) => { - pub struct $name; - mock_account!(# $name, $convert); - }; - ($name:ident ( $($field:ty),* ), $convert:expr) => { - pub struct $name($(pub $field),*); - mock_account!(# $name, $convert); - }; - (# $name:ident, $convert:expr) => { - impl From<$name> for MockAccount { - fn from(value: $name) -> MockAccount { - $convert(value) - } - } - - impl From<$name> for sp_core::H160 { - fn from(value: $name) -> sp_core::H160 { - MockAccount::from(value).into() - } - } - - impl From<$name> for sp_core::H256 { - fn from(value: $name) -> sp_core::H256 { - MockAccount::from(value).into() - } - } - }; -} - -mock_account!(Zero, |_| MockAccount::zero()); -mock_account!(Alice, |_| H160::repeat_byte(0xAA).into()); -mock_account!(Bob, |_| H160::repeat_byte(0xBB).into()); -mock_account!(Charlie, |_| H160::repeat_byte(0xCC).into()); -mock_account!(David, |_| H160::repeat_byte(0xDD).into()); - -mock_account!(Precompile1, |_| MockAccount::from_u64(1)); - -mock_account!(CryptoAlith, |_| H160::from(hex_literal::hex!( - "f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac" -)) -.into()); -mock_account!(CryptoBaltathar, |_| H160::from(hex_literal::hex!( - "3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0" -)) -.into()); -mock_account!(CryptoCarleth, |_| H160::from(hex_literal::hex!( - "798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc" -)) -.into()); - -mock_account!( - AddressInPrefixedSet(u32, u128), - |value: AddressInPrefixedSet| { - let prefix: u32 = value.0; - let index: u128 = value.1; - - let mut buffer = Vec::with_capacity(20); // 160 bits - - buffer.extend_from_slice(&prefix.to_be_bytes()); - buffer.extend_from_slice(&index.to_be_bytes()); - - assert_eq!(buffer.len(), 20, "address buffer should have len of 20"); - - H160::from_slice(&buffer).into() - } -); - -pub fn alith_secret_key() -> [u8; 32] { - hex_literal::hex!("5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133") -} - -pub fn baltathar_secret_key() -> [u8; 32] { - hex_literal::hex!("8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b") -} - -pub fn charleth_secret_key() -> [u8; 32] { - hex_literal::hex!("0b6e18cafb6ed99687ec547bd28139cafdd2bffe70e6b688025de6b445aa5c5b") -} diff --git a/precompiles/utils/src/testing/execution.rs b/precompiles/utils/src/testing/execution.rs deleted file mode 100644 index e37c207557..0000000000 --- a/precompiles/utils/src/testing/execution.rs +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - solidity::codec::Codec, - testing::{decode_revert_message, MockHandle, PrettyLog, SubcallHandle, SubcallTrait}, -}; -use fp_evm::{ - Context, ExitError, ExitSucceed, Log, PrecompileFailure, PrecompileOutput, PrecompileResult, - PrecompileSet, -}; -use sp_core::{H160, U256}; -use sp_std::boxed::Box; - -#[must_use] -pub struct PrecompilesTester<'p, P> { - precompiles: &'p P, - handle: MockHandle, - - target_gas: Option, - subcall_handle: Option, - - expected_cost: Option, - expected_logs: Option>, - static_call: bool, -} - -impl<'p, P: PrecompileSet> PrecompilesTester<'p, P> { - pub fn new( - precompiles: &'p P, - from: impl Into, - to: impl Into, - data: Vec, - ) -> Self { - let to = to.into(); - let mut handle = MockHandle::new( - to, - Context { - address: to, - caller: from.into(), - apparent_value: U256::zero(), - }, - ); - - handle.input = data; - - Self { - precompiles, - handle, - - target_gas: None, - subcall_handle: None, - - expected_cost: None, - expected_logs: None, - static_call: false, - } - } - - pub fn with_value(mut self, value: impl Into) -> Self { - self.handle.context.apparent_value = value.into(); - self - } - - pub fn with_subcall_handle(mut self, subcall_handle: impl SubcallTrait) -> Self { - self.subcall_handle = Some(Box::new(subcall_handle)); - self - } - - pub fn with_target_gas(mut self, target_gas: Option) -> Self { - self.target_gas = target_gas; - self - } - - pub fn with_static_call(mut self, static_call: bool) -> Self { - self.static_call = static_call; - self - } - - pub fn expect_cost(mut self, cost: u64) -> Self { - self.expected_cost = Some(cost); - self - } - - pub fn expect_no_logs(mut self) -> Self { - self.expected_logs = Some(vec![]); - self - } - - pub fn expect_log(mut self, log: Log) -> Self { - self.expected_logs = Some({ - let mut logs = self.expected_logs.unwrap_or_default(); - logs.push(PrettyLog(log)); - logs - }); - self - } - - fn assert_optionals(&self) { - if let Some(cost) = &self.expected_cost { - assert_eq!(&self.handle.gas_used, cost); - } - - if let Some(logs) = &self.expected_logs { - similar_asserts::assert_eq!(&self.handle.logs, logs); - } - } - - fn execute(&mut self) -> Option { - let handle = &mut self.handle; - handle.subcall_handle = self.subcall_handle.take(); - handle.is_static = self.static_call; - - if let Some(gas_limit) = self.target_gas { - handle.gas_limit = gas_limit; - } - - let res = self.precompiles.execute(handle); - - self.subcall_handle = handle.subcall_handle.take(); - - res - } - - /// Execute the precompile set and expect some precompile to have been executed, regardless of the - /// result. - pub fn execute_some(mut self) { - let res = self.execute(); - assert!(res.is_some()); - self.assert_optionals(); - } - - /// Execute the precompile set and expect no precompile to have been executed. - pub fn execute_none(mut self) { - let res = self.execute(); - assert!(res.is_some()); - self.assert_optionals(); - } - - /// Execute the precompile set and check it returns provided output. - pub fn execute_returns_raw(mut self, output: Vec) { - let res = self.execute(); - - match res { - Some(Err(PrecompileFailure::Revert { output, .. })) => { - let decoded = decode_revert_message(&output); - eprintln!( - "Revert message (bytes): {:?}", - sp_core::hexdisplay::HexDisplay::from(&decoded) - ); - eprintln!( - "Revert message (string): {:?}", - core::str::from_utf8(decoded).ok() - ); - panic!("Shouldn't have reverted"); - } - Some(Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: execution_output, - })) => { - if execution_output != output { - eprintln!( - "Output (bytes): {:?}", - sp_core::hexdisplay::HexDisplay::from(&execution_output) - ); - eprintln!( - "Output (string): {:?}", - core::str::from_utf8(&execution_output).ok() - ); - panic!("Output doesn't match"); - } - } - other => panic!("Unexpected result: {:?}", other), - } - - self.assert_optionals(); - } - - /// Execute the precompile set and check it returns provided Solidity encoded output. - pub fn execute_returns(self, output: impl Codec) { - self.execute_returns_raw(crate::solidity::encode_return_value(output)) - } - - /// Execute the precompile set and check if it reverts. - /// Take a closure allowing to perform custom matching on the output. - pub fn execute_reverts(mut self, check: impl Fn(&[u8]) -> bool) { - let res = self.execute(); - - match res { - Some(Err(PrecompileFailure::Revert { output, .. })) => { - let decoded = decode_revert_message(&output); - if !check(decoded) { - eprintln!( - "Revert message (bytes): {:?}", - sp_core::hexdisplay::HexDisplay::from(&decoded) - ); - eprintln!( - "Revert message (string): {:?}", - core::str::from_utf8(decoded).ok() - ); - panic!("Revert reason doesn't match !"); - } - } - other => panic!("Didn't revert, instead returned {:?}", other), - } - - self.assert_optionals(); - } - - /// Execute the precompile set and check it returns provided output. - pub fn execute_error(mut self, error: ExitError) { - let res = self.execute(); - assert_eq!( - res, - Some(Err(PrecompileFailure::Error { exit_status: error })) - ); - self.assert_optionals(); - } -} - -pub trait PrecompileTesterExt: PrecompileSet + Sized { - fn prepare_test( - &self, - from: impl Into, - to: impl Into, - data: impl Into>, - ) -> PrecompilesTester; -} - -impl PrecompileTesterExt for T { - fn prepare_test( - &self, - from: impl Into, - to: impl Into, - data: impl Into>, - ) -> PrecompilesTester { - PrecompilesTester::new(self, from, to, data.into()) - } -} diff --git a/precompiles/utils/src/testing/handle.rs b/precompiles/utils/src/testing/handle.rs deleted file mode 100644 index f03e7cee6e..0000000000 --- a/precompiles/utils/src/testing/handle.rs +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::testing::PrettyLog; -use evm::{ExitRevert, ExitSucceed}; -use fp_evm::{Context, ExitError, ExitReason, Log, PrecompileHandle, Transfer}; -use sp_core::{H160, H256}; -use sp_std::boxed::Box; - -#[derive(Debug, Clone)] -pub struct Subcall { - pub address: H160, - pub transfer: Option, - pub input: Vec, - pub target_gas: Option, - pub is_static: bool, - pub context: Context, -} - -#[derive(Debug, Clone)] -pub struct SubcallOutput { - pub reason: ExitReason, - pub output: Vec, - pub cost: u64, - pub logs: Vec, -} - -impl SubcallOutput { - pub fn revert() -> Self { - Self { - reason: ExitReason::Revert(ExitRevert::Reverted), - output: Vec::new(), - cost: 0, - logs: Vec::new(), - } - } - - pub fn succeed() -> Self { - Self { - reason: ExitReason::Succeed(ExitSucceed::Returned), - output: Vec::new(), - cost: 0, - logs: Vec::new(), - } - } - - pub fn out_of_gas() -> Self { - Self { - reason: ExitReason::Error(ExitError::OutOfGas), - output: Vec::new(), - cost: 0, - logs: Vec::new(), - } - } -} - -pub trait SubcallTrait: FnMut(Subcall) -> SubcallOutput + 'static {} - -impl SubcallOutput + 'static> SubcallTrait for T {} - -pub type SubcallHandle = Box; - -/// Mock handle to write tests for precompiles. -pub struct MockHandle { - pub gas_limit: u64, - pub gas_used: u64, - pub logs: Vec, - pub subcall_handle: Option, - pub code_address: H160, - pub input: Vec, - pub context: Context, - pub is_static: bool, -} - -impl MockHandle { - pub fn new(code_address: H160, context: Context) -> Self { - Self { - gas_limit: u64::MAX, - gas_used: 0, - logs: vec![], - subcall_handle: None, - code_address, - input: Vec::new(), - context, - is_static: false, - } - } -} - -impl PrecompileHandle for MockHandle { - /// Perform subcall in provided context. - /// Precompile specifies in which context the subcall is executed. - fn call( - &mut self, - address: H160, - transfer: Option, - input: Vec, - target_gas: Option, - is_static: bool, - context: &Context, - ) -> (ExitReason, Vec) { - if self - .record_cost(crate::evm::costs::call_cost( - context.apparent_value, - &evm::Config::london(), - )) - .is_err() - { - return (ExitReason::Error(ExitError::OutOfGas), vec![]); - } - - match &mut self.subcall_handle { - Some(handle) => { - let SubcallOutput { - reason, - output, - cost, - logs, - } = handle(Subcall { - address, - transfer, - input, - target_gas, - is_static, - context: context.clone(), - }); - - if self.record_cost(cost).is_err() { - return (ExitReason::Error(ExitError::OutOfGas), vec![]); - } - - for log in logs { - self.log(log.address, log.topics, log.data) - .expect("cannot fail"); - } - - (reason, output) - } - None => panic!("no subcall handle registered"), - } - } - - fn record_cost(&mut self, cost: u64) -> Result<(), ExitError> { - self.gas_used += cost; - - if self.gas_used > self.gas_limit { - Err(ExitError::OutOfGas) - } else { - Ok(()) - } - } - - fn remaining_gas(&self) -> u64 { - self.gas_limit - self.gas_used - } - - fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { - self.logs.push(PrettyLog(Log { - address, - topics, - data, - })); - Ok(()) - } - - /// Retreive the code address (what is the address of the precompile being called). - fn code_address(&self) -> H160 { - self.code_address - } - - /// Retreive the input data the precompile is called with. - fn input(&self) -> &[u8] { - &self.input - } - - /// Retreive the context in which the precompile is executed. - fn context(&self) -> &Context { - &self.context - } - - /// Is the precompile call is done statically. - fn is_static(&self) -> bool { - self.is_static - } - - /// Retreive the gas limit of this call. - fn gas_limit(&self) -> Option { - Some(self.gas_limit) - } - - fn record_external_cost( - &mut self, - _ref_time: Option, - _proof_size: Option, - _storage_growth: Option, - ) -> Result<(), ExitError> { - Ok(()) - } - - fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} -} diff --git a/precompiles/utils/src/testing/mod.rs b/precompiles/utils/src/testing/mod.rs deleted file mode 100644 index 89e826a4fb..0000000000 --- a/precompiles/utils/src/testing/mod.rs +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -pub mod account; -pub mod execution; -pub mod handle; -pub mod modifier; -mod solidity; - -pub use account::*; -pub use execution::*; -pub use handle::*; -pub use modifier::*; -pub use solidity::{check_precompile_implements_solidity_interfaces, compute_selector}; - -use fp_evm::Log; - -pub fn decode_revert_message(encoded: &[u8]) -> &[u8] { - let encoded_len = encoded.len(); - // selector 4 + offset 32 + string length 32 - if encoded_len > 68 { - let message_len = encoded[36..68].iter().sum::(); - if encoded_len >= 68 + message_len as usize { - return &encoded[68..68 + message_len as usize]; - } - } - b"decode_revert_message: error" -} - -#[derive(Clone, PartialEq, Eq)] -pub struct PrettyLog(Log); - -impl core::fmt::Debug for PrettyLog { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - let bytes = self - .0 - .data - .iter() - .map(|b| format!("{:02X}", b)) - .collect::>() - .join(""); - - let message = String::from_utf8(self.0.data.clone()).ok(); - - f.debug_struct("Log") - .field("address", &self.0.address) - .field("topics", &self.0.topics) - .field("data", &bytes) - .field("data_utf8", &message) - .finish() - } -} - -/// Panics if an event is not found in the system log of events -#[macro_export] -macro_rules! assert_event_emitted { - ($event:expr) => { - match &$event { - e => { - assert!( - $crate::mock::events().iter().find(|x| *x == e).is_some(), - "Event {:?} was not found in events: \n {:?}", - e, - $crate::mock::events() - ); - } - } - }; -} - -// Panics if an event is found in the system log of events -#[macro_export] -macro_rules! assert_event_not_emitted { - ($event:expr) => { - match &$event { - e => { - assert!( - $crate::mock::events().iter().find(|x| *x == e).is_none(), - "Event {:?} was found in events: \n {:?}", - e, - $crate::mock::events() - ); - } - } - }; -} diff --git a/precompiles/utils/src/testing/modifier.rs b/precompiles/utils/src/testing/modifier.rs deleted file mode 100644 index b0a795333b..0000000000 --- a/precompiles/utils/src/testing/modifier.rs +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - solidity::codec::Writer, - testing::{decode_revert_message, MockHandle}, -}; -use fp_evm::{Context, PrecompileFailure, PrecompileSet}; -use sp_core::{H160, U256}; - -pub struct PrecompilesModifierTester

{ - precompiles: P, - handle: MockHandle, -} - -impl PrecompilesModifierTester

{ - pub fn new(precompiles: P, from: impl Into, to: impl Into) -> Self { - let to = to.into(); - let mut handle = MockHandle::new( - to, - Context { - address: to, - caller: from.into(), - apparent_value: U256::zero(), - }, - ); - - handle.gas_limit = u64::MAX; - - Self { - precompiles, - handle, - } - } - - fn is_view(&mut self, selector: u32) -> bool { - // View: calling with static should not revert with static-related message. - let handle = &mut self.handle; - handle.is_static = true; - handle.context.apparent_value = U256::zero(); - handle.input = Writer::new_with_selector(selector).build(); - - let res = self.precompiles.execute(handle); - - match res { - Some(Err(PrecompileFailure::Revert { output, .. })) => { - let decoded = decode_revert_message(&output); - - dbg!(decoded) != b"Can't call non-static function in static context" - } - Some(_) => true, - None => panic!("tried to check view modifier on unknown precompile"), - } - } - - fn is_payable(&mut self, selector: u32) -> bool { - // Payable: calling with value should not revert with payable-related message. - let handle = &mut self.handle; - handle.is_static = false; - handle.context.apparent_value = U256::one(); - handle.input = Writer::new_with_selector(selector).build(); - - let res = self.precompiles.execute(handle); - - match res { - Some(Err(PrecompileFailure::Revert { output, .. })) => { - let decoded = decode_revert_message(&output); - - decoded != b"Function is not payable" - } - Some(_) => true, - None => panic!("tried to check payable modifier on unknown precompile"), - } - } - - pub fn test_view_modifier(&mut self, selectors: &[u32]) { - for &s in selectors { - assert!( - self.is_view(s), - "Function doesn't behave like a view function." - ); - assert!( - !self.is_payable(s), - "Function doesn't behave like a non-payable function." - ) - } - } - - pub fn test_payable_modifier(&mut self, selectors: &[u32]) { - for &s in selectors { - assert!( - !self.is_view(s), - "Function doesn't behave like a non-view function." - ); - assert!( - self.is_payable(s), - "Function doesn't behave like a payable function." - ); - } - } - - pub fn test_default_modifier(&mut self, selectors: &[u32]) { - for &s in selectors { - assert!( - !self.is_view(s), - "Function doesn't behave like a non-view function." - ); - assert!( - !self.is_payable(s), - "Function doesn't behave like a non-payable function." - ); - } - } -} diff --git a/precompiles/utils/src/testing/solidity.rs b/precompiles/utils/src/testing/solidity.rs deleted file mode 100644 index 34d20c7e69..0000000000 --- a/precompiles/utils/src/testing/solidity.rs +++ /dev/null @@ -1,375 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Utility module to interact with solidity file. - -use sp_io::hashing::keccak_256; -use std::{ - collections::HashMap, - fs::File, - io::{BufRead, BufReader, Read}, -}; - -pub fn check_precompile_implements_solidity_interfaces( - files: &[&'static str], - supports_selector: F, -) where - F: Fn(u32) -> bool, -{ - for file in files { - for solidity_fn in get_selectors(file) { - assert_eq!( - solidity_fn.compute_selector_hex(), - solidity_fn.docs_selector, - "documented selector for '{}' did not match in file '{}'", - solidity_fn.signature(), - file, - ); - - let selector = solidity_fn.compute_selector(); - if !supports_selector(selector) { - panic!( - "precompile don't support selector {selector:x} for function '{}' listed in file\ - {file}", - solidity_fn.signature(), - ) - } - } - } -} - -/// Represents a declared custom type struct within a solidity file -#[derive(Clone, Default, Debug)] -pub struct SolidityStruct { - /// Struct name - pub name: String, - /// List of parameter types - pub params: Vec, - /// Is struct an enum - pub is_enum: bool, -} - -impl SolidityStruct { - /// Returns the representative signature for the solidity struct - pub fn signature(&self) -> String { - if self.is_enum { - "uint8".to_string() - } else { - format!("({})", self.params.join(",")) - } - } -} - -/// Represents a declared function within a solidity file -#[derive(Clone, Default)] -pub struct SolidityFunction { - /// Function name - pub name: String, - /// List of function parameter types - pub args: Vec, - /// The declared selector in the file - pub docs_selector: String, -} - -impl SolidityFunction { - /// Returns the representative signature for the solidity function - pub fn signature(&self) -> String { - format!("{}({})", self.name, self.args.join(",")) - } - - /// Computes the selector code for the solidity function - pub fn compute_selector(&self) -> u32 { - compute_selector(&self.signature()) - } - - /// Computes the selector code as a hex string for the solidity function - pub fn compute_selector_hex(&self) -> String { - format!("{:0>8x}", self.compute_selector()) - } -} - -/// Computes a solidity selector from a given string -pub fn compute_selector(v: &str) -> u32 { - let output = keccak_256(v.as_bytes()); - let mut buf = [0u8; 4]; - buf.clone_from_slice(&output[..4]); - u32::from_be_bytes(buf) -} - -/// Returns a list of [SolidityFunction] defined in a solidity file -pub fn get_selectors(filename: &str) -> Vec { - let file = File::open(filename) - .unwrap_or_else(|e| panic!("failed opening file '{}': {}", filename, e)); - get_selectors_from_reader(file) -} - -/// Attempts to lookup a custom struct and returns its primitive signature -fn try_lookup_custom_type(word: &str, custom_types: &HashMap) -> String { - match word.strip_suffix("[]") { - Some(word) => { - if let Some(t) = custom_types.get(word) { - return format!("{}[]", t.signature()); - } - } - None => { - if let Some(t) = custom_types.get(word) { - return t.signature(); - } - } - }; - - word.to_string() -} - -fn get_selectors_from_reader(reader: R) -> Vec { - #[derive(Clone, Copy)] - enum Stage { - Start, - Enum, - Struct, - StructParams, - FnName, - Args, - } - #[derive(Clone, Copy)] - enum Pair { - First, - Second, - } - impl Pair { - fn next(&mut self) { - *self = match self { - Pair::First => Pair::Second, - Pair::Second => Pair::First, - } - } - } - - let reader = BufReader::new(reader); - let mut functions = vec![]; - let mut custom_types = HashMap::new(); - let mut solidity_struct = SolidityStruct::default(); - - let mut stage = Stage::Start; - let mut pair = Pair::First; - let mut solidity_fn = SolidityFunction::default(); - for line in reader.lines() { - let line = line.expect("failed unwrapping line").trim().to_string(); - // identify declared selector - if line.starts_with("/// @custom:selector ") && matches!(stage, Stage::Start) { - solidity_fn.docs_selector = line.replace("/// @custom:selector ", "").to_string(); - } - - // skip comments - if line.starts_with("//") { - continue; - } - - for word in line.split(&[';', ',', '(', ')', ' ']) { - // skip whitespace - if word.trim().is_empty() { - continue; - } - match (stage, pair, word) { - // parse custom type enums - (Stage::Start, Pair::First, "enum") => { - stage = Stage::Enum; - pair.next(); - } - (Stage::Enum, Pair::Second, _) => { - custom_types.insert( - word.to_string(), - SolidityStruct { - name: word.to_string(), - is_enum: true, - params: vec![], - }, - ); - stage = Stage::Start; - pair = Pair::First; - } - - // parse custom type structs - (Stage::Start, Pair::First, "struct") => { - stage = Stage::Struct; - pair.next(); - } - (Stage::Struct, Pair::Second, _) => { - solidity_struct.name = word.to_string(); - stage = Stage::StructParams; - pair.next(); - } - (Stage::StructParams, Pair::First, "{") => (), - (Stage::StructParams, Pair::First, "}") => { - custom_types.insert(solidity_struct.name.clone(), solidity_struct); - stage = Stage::Start; - solidity_struct = SolidityStruct::default(); - } - (Stage::StructParams, Pair::First, _) => { - let param = try_lookup_custom_type(word, &custom_types); - solidity_struct.params.push(param); - pair.next(); - } - (Stage::StructParams, Pair::Second, _) => { - pair.next(); - } - - // parse function - (Stage::Start, Pair::First, "function") => { - stage = Stage::FnName; - pair.next(); - } - (Stage::FnName, Pair::Second, _) => { - solidity_fn.name = word.to_string(); - stage = Stage::Args; - pair.next(); - } - (Stage::Args, Pair::First, "external") => { - functions.push(solidity_fn); - stage = Stage::Start; - pair = Pair::First; - solidity_fn = SolidityFunction::default() - } - (Stage::Args, Pair::First, _) => { - let mut arg = word.to_string(); - arg = try_lookup_custom_type(&arg, &custom_types); - - solidity_fn.args.push(arg); - pair.next(); - } - (Stage::Args, Pair::Second, "memory" | "calldata" | "storage") => (), - (Stage::Args, Pair::Second, _) => pair.next(), - _ => { - stage = Stage::Start; - pair = Pair::First; - solidity_fn = SolidityFunction::default() - } - } - } - } - - functions -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_selectors_are_parsed() { - let actual = get_selectors("tests/solidity_test.sol") - .into_iter() - .map(|sol_fn| { - ( - sol_fn.compute_selector_hex(), - sol_fn.docs_selector.clone(), - sol_fn.signature(), - ) - }) - .collect::>(); - let expected = vec![ - ( - String::from("f7af8d91"), - String::from(""), - String::from("fnNoArgs()"), - ), - ( - String::from("d43a9a43"), - String::from("c4921133"), - String::from("fnOneArg(address)"), - ), - ( - String::from("40d6a43d"), - String::from("67ea837e"), - String::from("fnTwoArgs(address,uint256)"), - ), - ( - String::from("cee150c8"), - String::from("d6b423d9"), - String::from("fnSameArgs(uint64,uint64)"), - ), - ( - String::from("c6024207"), - String::from("b9904a86"), - String::from("fnOneArgSameLine(uint64)"), - ), - ( - String::from("fcbc04c3"), - String::from("28f0c44e"), - String::from("fnTwoArgsSameLine(uint64,bytes32)"), - ), - ( - String::from("c590304c"), - String::from("06f0c1ce"), - String::from("fnTwoArgsSameLineExternalSplit(uint64,bytes32)"), - ), - ( - String::from("a19a07e1"), - String::from("18001a4e"), - String::from("fnMemoryArrayArgs(address[],uint256[],bytes[])"), - ), - ( - String::from("ec26cf1c"), - String::from("1ea61a4e"), - String::from("fnCalldataArgs(string,bytes[])"), - ), - ( - String::from("f29f96de"), - String::from("d8af1a4e"), - String::from("fnCustomArgs((uint8,bytes[]),bytes[],uint64)"), - ), - ( - String::from("d751d651"), - String::from("e8af1642"), - String::from("fnEnumArgs(uint8,uint64)"), - ), - ( - String::from("b2c9f1a3"), - String::from("550c1a4e"), - String::from( - "fnCustomArgsMultiple((uint8,bytes[]),(address[],uint256[],bytes[]),bytes[],\ - uint64)", - ), - ), - ( - String::from("d5363eee"), - String::from("77af1a40"), - String::from("fnCustomArrayArgs((uint8,bytes[])[],bytes[])"), - ), - ( - String::from("b82da727"), - String::from("80af0a40"), - String::from( - "fnCustomComposedArg(((uint8,bytes[]),\ - (address[],uint256[],bytes[])[]),uint64)", - ), - ), - ( - String::from("586a2193"), - String::from("97baa040"), - String::from( - "fnCustomComposedArrayArg(((uint8,bytes[]),\ - (address[],uint256[],bytes[])[])[],uint64)", - ), - ), - ]; - - assert_eq!(expected, actual); - } -} diff --git a/precompiles/utils/tests-external/Cargo.toml b/precompiles/utils/tests-external/Cargo.toml deleted file mode 100644 index b113dd5145..0000000000 --- a/precompiles/utils/tests-external/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "precompile-utils-tests-external" -authors = { workspace = true } -edition = "2021" -version = "0.1.0" - -[lib] -path = "./lib.rs" - -[dependencies] -evm = { workspace = true, features = ["with-codec"] } -hex-literal = { workspace = true } -scale-codec = { package = "parity-scale-codec", workspace = true, features = ["max-encoded-len"] } -scale-info = { workspace = true, features = ["derive"] } -# Substrate -sp-core = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } -# Substrate FRAME -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } -pallet-timestamp = { workspace = true } -# Frontier -fp-evm = { workspace = true } -pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } -precompile-utils = { workspace = true, features = ["testing"] } diff --git a/precompiles/utils/tests-external/lib.rs b/precompiles/utils/tests-external/lib.rs deleted file mode 100644 index 43f2c3fec7..0000000000 --- a/precompiles/utils/tests-external/lib.rs +++ /dev/null @@ -1,439 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2019-2022 Moonsong Labs. -// Copyright (c) 2023 Parity Technologies (UK) Ltd. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#![cfg(test)] - -use std::{cell::RefCell, rc::Rc}; - -// Substrate -use frame_support::{construct_runtime, parameter_types, traits::Everything, weights::Weight}; -use sp_core::{H160, H256, U256}; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, Perbill, -}; -// Frontier -use fp_evm::{ExitReason, ExitRevert, PrecompileFailure, PrecompileHandle}; -use pallet_evm::{EnsureAddressNever, EnsureAddressRoot}; -use precompile_utils::{ - precompile_set::*, - solidity::{codec::Writer, revert::revert}, - testing::*, - EvmResult, -}; - -pub type AccountId = MockAccount; -pub type Balance = u128; - -construct_runtime!( - pub enum Runtime { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Event}, - Evm: pallet_evm::{Pallet, Call, Storage, Event}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - } -); - -parameter_types! { - pub const BlockHashCount: u32 = 250; - pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 1); - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - pub const SS58Prefix: u8 = 42; -} - -impl frame_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = frame_system::mocking::MockBlock; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - type RuntimeTask = RuntimeTask; - type SingleBlockMigrations = (); - type MultiBlockMigrator = (); - type PreInherents = (); - type PostInherents = (); - type PostTransactions = (); -} - -parameter_types! { - pub const ExistentialDeposit: u128 = 0; -} -impl pallet_balances::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Balance = Balance; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type ReserveIdentifier = [u8; 4]; - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type RuntimeFreezeReason = (); - type MaxLocks = (); - type MaxReserves = (); - type MaxFreezes = (); -} - -#[derive(Debug, Clone)] -pub struct MockPrecompile; - -#[precompile_utils::precompile] -impl MockPrecompile { - // a3cab0dd - #[precompile::public("subcall()")] - fn subcall(handle: &mut impl PrecompileHandle) -> EvmResult { - match handle.call( - handle.code_address(), - None, - // calls subcallLayer2() - Writer::new_with_selector(0x0b93381bu32).build(), - None, - false, - &evm::Context { - caller: handle.code_address(), - address: handle.code_address(), - apparent_value: 0.into(), - }, - ) { - (ExitReason::Succeed(_), _) => Ok(()), - (ExitReason::Revert(_), v) => Err(PrecompileFailure::Revert { - exit_status: ExitRevert::Reverted, - output: v, - }), - _ => Err(revert("unexpected error")), - } - } - - // 0b93381b - #[precompile::public("success()")] - fn success(_: &mut impl PrecompileHandle) -> EvmResult { - Ok(()) - } -} - -struct MockPrecompileHandle; -impl PrecompileHandle for MockPrecompileHandle { - fn call( - &mut self, - _: H160, - _: Option, - _: Vec, - _: Option, - _: bool, - _: &evm::Context, - ) -> (ExitReason, Vec) { - unimplemented!() - } - - fn record_cost(&mut self, _: u64) -> Result<(), evm::ExitError> { - Ok(()) - } - - fn record_external_cost( - &mut self, - _ref_time: Option, - _proof_size: Option, - _storage_growth: Option, - ) -> Result<(), fp_evm::ExitError> { - Ok(()) - } - - fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} - - fn remaining_gas(&self) -> u64 { - unimplemented!() - } - - fn log(&mut self, _: H160, _: Vec, _: Vec) -> Result<(), evm::ExitError> { - unimplemented!() - } - - fn code_address(&self) -> H160 { - unimplemented!() - } - - fn input(&self) -> &[u8] { - unimplemented!() - } - - fn context(&self) -> &evm::Context { - unimplemented!() - } - - fn is_static(&self) -> bool { - true - } - - fn gas_limit(&self) -> Option { - unimplemented!() - } -} - -pub type Precompiles = PrecompileSetBuilder< - R, - ( - PrecompileAt, MockPrecompile>, - PrecompileAt, MockPrecompile, CallableByContract>, - PrecompileAt, MockPrecompile, CallableByPrecompile>, - PrecompileAt, MockPrecompile, SubcallWithMaxNesting<1>>, - ), ->; - -pub type PrecompileCall = MockPrecompileCall; - -const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; - -parameter_types! { - pub BlockGasLimit: U256 = U256::from(u64::MAX); - pub PrecompilesValue: Precompiles = Precompiles::new(); - pub const WeightPerGas: Weight = Weight::from_parts(1, 0); - pub GasLimitPovSizeRatio: u64 = { - let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); - block_gas_limit.saturating_div(MAX_POV_SIZE) - }; -} - -impl pallet_evm::Config for Runtime { - type FeeCalculator = (); - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type WeightPerGas = WeightPerGas; - type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; - type CallOrigin = EnsureAddressRoot; - type WithdrawOrigin = EnsureAddressNever; - type AddressMapping = AccountId; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type PrecompilesType = Precompiles; - type PrecompilesValue = PrecompilesValue; - type ChainId = (); - type BlockGasLimit = BlockGasLimit; - type Runner = pallet_evm::runner::stack::Runner; - type OnChargeTransaction = (); - type OnCreate = (); - type FindAuthor = (); - type GasLimitPovSizeRatio = GasLimitPovSizeRatio; - type SuicideQuickClearLimit = ConstU32<0>; - type Timestamp = Timestamp; - type WeightInfo = pallet_evm::weights::SubstrateWeight; -} - -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} - -#[derive(Default)] -struct ExtBuilder {} - -impl ExtBuilder { - fn build(self) -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default() - .build_storage() - .expect("Frame system builds valid default genesis config"); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| { - System::set_block_number(1); - }); - ext - } -} - -fn precompiles() -> Precompiles { - PrecompilesValue::get() -} - -#[test] -fn default_checks_succeed_when_called_by_eoa() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test(Alice, H160::from_low_u64_be(1), PrecompileCall::success {}) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_returns(()) - }) -} - -#[test] -fn default_checks_revert_when_called_by_precompile() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test( - H160::from_low_u64_be(1), - H160::from_low_u64_be(1), - PrecompileCall::success {}, - ) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_reverts(|r| r == b"Function not callable by precompiles") - }) -} - -#[test] -fn default_checks_revert_when_called_by_contract() { - ExtBuilder::default().build().execute_with(|| { - pallet_evm::Pallet::::create_account( - Alice.into(), - hex_literal::hex!("1460006000fd").to_vec(), - ); - - precompiles() - .prepare_test(Alice, H160::from_low_u64_be(1), PrecompileCall::success {}) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_reverts(|r| r == b"Function not callable by smart contracts") - }) -} - -#[test] -fn default_checks_revert_when_doing_subcall() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test(Alice, H160::from_low_u64_be(1), PrecompileCall::subcall {}) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_reverts(|r| r == b"subcalls disabled for this precompile") - }) -} - -#[test] -fn callable_by_contract_works() { - ExtBuilder::default().build().execute_with(|| { - pallet_evm::Pallet::::create_account( - Alice.into(), - hex_literal::hex!("1460006000fd").to_vec(), - ); - - precompiles() - .prepare_test(Alice, H160::from_low_u64_be(2), PrecompileCall::success {}) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_returns(()) - }) -} - -#[test] -fn callable_by_precompile_works() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test( - H160::from_low_u64_be(3), - H160::from_low_u64_be(3), - PrecompileCall::success {}, - ) - .with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall")) - .execute_returns(()) - }) -} - -#[test] -fn subcalls_works_when_allowed() { - ExtBuilder::default().build().execute_with(|| { - let subcall_occured = Rc::new(RefCell::new(false)); - { - let subcall_occured = Rc::clone(&subcall_occured); - precompiles() - .prepare_test(Alice, H160::from_low_u64_be(4), PrecompileCall::subcall {}) - .with_subcall_handle(move |Subcall { .. }| { - *subcall_occured.borrow_mut() = true; - SubcallOutput::succeed() - }) - .execute_returns(()); - } - assert!(*subcall_occured.borrow()); - }) -} - -#[test] -fn get_address_type_works_for_eoa() { - ExtBuilder::default().build().execute_with(|| { - let addr = H160::repeat_byte(0x1d); - assert_eq!( - AddressType::EOA, - get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") - ); - }) -} - -#[test] -fn get_address_type_works_for_precompile() { - ExtBuilder::default().build().execute_with(|| { - let addr = H160::repeat_byte(0x1d); - pallet_evm::AccountCodes::::insert(addr, vec![0x60, 0x00, 0x60, 0x00, 0xfd]); - assert_eq!( - AddressType::Precompile, - get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") - ); - }) -} - -#[test] -fn get_address_type_works_for_smart_contract() { - ExtBuilder::default().build().execute_with(|| { - let addr = H160::repeat_byte(0x1d); - - // length > 5 - pallet_evm::AccountCodes::::insert( - addr, - vec![0x60, 0x00, 0x60, 0x00, 0xfd, 0xff, 0xff], - ); - assert_eq!( - AddressType::Contract, - get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") - ); - - // length < 5 - pallet_evm::AccountCodes::::insert(addr, vec![0x60, 0x00, 0x60]); - assert_eq!( - AddressType::Contract, - get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") - ); - }) -} - -#[test] -fn get_address_type_works_for_unknown() { - ExtBuilder::default().build().execute_with(|| { - let addr = H160::repeat_byte(0x1d); - pallet_evm::AccountCodes::::insert(addr, vec![0x11, 0x00, 0x60, 0x00, 0xfd]); - assert_eq!( - AddressType::Unknown, - get_address_type::(&mut MockPrecompileHandle, addr).expect("OOG") - ); - }) -} diff --git a/precompiles/utils/tests/solidity_test.sol b/precompiles/utils/tests/solidity_test.sol deleted file mode 100644 index bd16b8487c..0000000000 --- a/precompiles/utils/tests/solidity_test.sol +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity >=0.8.3; - -/// @title Solidity test file with incorrectly defined selectors -interface SolidityTest { - /// A custom enum - enum CustomEnum0 { - A, - B, - C - } - - /// A custom type - struct CustomArg0 { - CustomEnum0 p0; - bytes[] p1; - } - - /// A custom type - struct CustomArg1 { - address[] p0; - uint256[] p1; - bytes[] p2; - } - - /// A composed custom type - struct CustomArg2 { - CustomArg0 p0; - CustomArg1[] p1; - } - - /// @dev Function without params and no selector - function fnNoArgs() external; - - /// @dev Function info - /// - /// @param arg0 Arg0 Description - /// @custom:selector c4921133 - function fnOneArg(address arg0) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 67ea837e - function fnTwoArgs(address arg0, uint256 arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector d6b423d9 - function fnSameArgs(uint64 arg0, uint64 arg1) external; - - /// @param arg0 Arg0 Description - /// @custom:selector b9904a86 - function fnOneArgSameLine(uint64 arg0) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 28f0c44e - function fnTwoArgsSameLine(uint64 arg0, bytes32 arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 06f0c1ce - function fnTwoArgsSameLineExternalSplit(uint64 arg0, bytes32 arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @param arg2 Arg2 Description - /// @custom:selector 18001a4e - function fnMemoryArrayArgs( - address[] memory arg0, - uint256[] memory arg1, - bytes[] memory arg2 - ) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 1ea61a4e - function fnCalldataArgs(string calldata arg0, bytes[] memory arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @param arg2 Arg2 Description - /// @custom:selector d8af1a4e - function fnCustomArgs( - CustomArg0 memory arg0, - bytes[] memory arg1, - uint64 arg2 - ) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector e8af1642 - function fnEnumArgs(CustomEnum0 arg0, uint64 arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @param arg2 Arg2 Description - /// @param arg3 Arg3 Description - /// @custom:selector 550c1a4e - function fnCustomArgsMultiple( - CustomArg0 memory arg0, - CustomArg1 memory arg1, - bytes[] memory arg2, - uint64 arg3 - ) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 77af1a40 - function fnCustomArrayArgs(CustomArg0[] memory arg0, bytes[] memory arg1) - external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 80af0a40 - function fnCustomComposedArg(CustomArg2 memory arg0, uint64 arg1) external; - - /// @param arg0 Arg0 Description - /// @param arg1 Arg1 Description - /// @custom:selector 97baa040 - function fnCustomComposedArrayArg(CustomArg2[] memory arg0, uint64 arg1) - external; -}