diff --git a/procedural/README.md b/procedural/README.md index e835ded..09a494a 100644 --- a/procedural/README.md +++ b/procedural/README.md @@ -56,6 +56,7 @@ Supported abstractions: | `EVM` | * `fp_rpc::EthereumRuntimeRPCApi`
* `fp_rpc::ConvertTransactionRuntimeApi` | * `RuntimeCall` -- runtime call generated by `construct_runtime` macro
* `Executive` -- `frame_executive::Executive` specification used by parachain system
* `Ethereum` -- `pallet_ethereum` pallet struct generated by `construct_runtime` macro | | `assets` | * `pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi`
* `pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi` | * `TransactionPayment` -- `pallet_transaction_payment` struct pallet generated by `construct_runtime` macro
* `RuntimeCall` -- runtime call generated by `construct_runtime` macro
* `Balance` -- type used for balance specification (e.g. in `pallet_balances` config) | | `consensus` | * `sp_consensus_aura::AuraApi`
* `sp_session::SessionKeys`
* `cumulus_primitives_aura::AuraUnincludedSegmentApi` (if `async-backing` feature is enabled) | * `SessionKeys` -- struct generated by `impl_opaque_keys` macro
* `Aura` -- `pallet_aura` struct pallet generated by `construct_runtime` macro (only if `async-backing` feature is not enabled)
* `SlotDuration` -- constant that is use for slot duration definition (only if `async-backing` feature is enabled)
* `ConsensusHook` -- type that is used in `cumulus_pallet_parachain_system::Config::ConsensusHook` (only if `async-backing` feature is enabled) | -| `system` | * `sp_api::Core`
* `sp_api::Metadata`
* `sp_block_builder::BlockBuilder`
* `sp_transaction_pool::runtime_api::TaggedTransactionQueue`
* `sp_offchain::OffchainWorkerApi`
* `frame_system_rpc_runtime_api::AccountNonceApi`
* `cumulus_primitives_core::CollectCollationInfo`
* `frame_try_runtime::TryRuntime` (under a `try-runtime` feature)
* `sp_genesis_builder::GenesisBuilder`
* `frame_system_benchmarking::Config` (under a `runtime-benchmarks` feature) | * `Executive` -- `frame_executive::Executive` specification used by parachain system
* `System` -- `frame_system` pallet struct generated by `construct_runtime` macro
* `ParachainSystem` -- `cumulus_pallet_parachain_system` pallet struct generated by `construct_runtime` macro
* `RuntimeVersion` -- runtime version, generated by `sp_version::runtime_version`
* `AccountId` -- account id type that was specified in `frame_system::Config`
* `Nonce` -- npnce type that was specified in `frame_system::Config`
* `RuntimeGenesisBuilder` -- type generated by `construct_runtime` macro. | +| `system` | * `sp_api::Core`
* `sp_api::Metadata`
* `sp_block_builder::BlockBuilder`
* `sp_transaction_pool::runtime_api::TaggedTransactionQueue`
* `sp_offchain::OffchainWorkerApi`
* `frame_system_rpc_runtime_api::AccountNonceApi`
* `cumulus_primitives_core::CollectCollationInfo`
* `frame_try_runtime::TryRuntime` (under a `try-runtime` feature)
* `sp_genesis_builder::GenesisBuilder`
* `frame_system_benchmarking::Config` (under a `runtime-benchmarks` feature) | * `Executive` -- `frame_executive::Executive` specification used by parachain system
* `System` -- `frame_system` pallet struct generated by `construct_runtime` macro
* `ParachainSystem` -- `cumulus_pallet_parachain_system` pallet struct generated by `construct_runtime` macro
* `RuntimeVersion` -- runtime version, generated by `sp_version::runtime_version`
* `AccountId` -- account id type that was specified in `frame_system::Config`
* `Nonce` -- nonce type that was specified in `frame_system::Config`
* `RuntimeGenesisBuilder` -- type generated by `construct_runtime` macro. | +| `benchmarks` | * `frame_benchmarking::Benchmark` (under `runtime-benchmarks` feature) | * `Assets` -- `palet_assets` pallet struct generated by `construct_runtime` macro
* `AssetManager` -- `pallet_asset_manager` pallet struct generated by `construct_runtime` macro
* `AssetType` -- struct that describes foreign assets in XCM configuration (e.g. the one that was passed to `AssetType` field in `AssetsConfig`
* `RuntimeOrigin` -- type generated by `construct_runtime` macro
* `RelayLocation` -- `Location` type pointing to the relaychain.
* `ParachainSystem` -- `cumulus_pallet_parachain_system` pallet struct generated by `construct_runtime` macro
* `ExistentialDeposit` -- type that decribes existential deposit (e.g. the one passed to `SystemConfig`)
* `AssetId` -- type that describes internal asset id (e.g `AssetId` passet to `AssetsConfig`)
* `XCMConfig` -- struct that implements `xcm_executor::Config`. If you are using pallet abstractions it is generated by XCM abstraction and called `XcmExecutorConfig`
* `AccountId` -- account id type that was specified in `frame_system::Config`
* `Cents` -- constant that represents 1/100 of your native token.
* `FeeAssetId` -- type that describes an asset to pay XCM fees in. If you used an abstraction macro for XCM support, it was generated along the way and named `FeeAssetId`.
* `TransactionByteFee` -- type that describes fee per byte of data. If you used an abstraction macro for assets support it was generated with the same name.| Also, this macro implements `frame_benchmarking::Benchmark` for all of the specified pallets. \ No newline at end of file diff --git a/procedural/src/apis/benchmark.rs b/procedural/src/apis/benchmark.rs index a7fc212..b02c104 100644 --- a/procedural/src/apis/benchmark.rs +++ b/procedural/src/apis/benchmark.rs @@ -1,31 +1,214 @@ +use proc_macro2::Ident; use quote::quote; +use syn::Item; + +use super::fetch_ident; #[derive(Default)] pub struct AbstractionState { - pub assets: bool, - pub xcm: bool, + pub benchmark_fields: Option, pub consensus: bool, } -pub fn construct_benchmarking_api(state: AbstractionState) -> proc_macro2::TokenStream { +pub struct BenchmarkAPIFields { + pub all_pallets_with_system: Ident, + pub xcm_fields: Option, +} + +impl TryFrom<&[Item]> for BenchmarkAPIFields { + type Error = &'static str; + + fn try_from(value: &[Item]) -> Result { + let mut all_pallets_with_system = None; + + for item in value { + match item { + Item::Type(ty) => { + if ty.ident == "AllPalletsWithSystem" { + all_pallets_with_system = Some(fetch_ident(&ty.ty)) + } + } + _ => (), + } + } + + let all_pallets_with_system = all_pallets_with_system + .ok_or("type `AllPalletsWithSystem` not specified, but required")?; + let xcm_fields = XCMBenchmarkAPIFields::try_from(value) + .map_err(|e| println!("{e:?}")) + .ok(); + + Ok(BenchmarkAPIFields { + all_pallets_with_system, + xcm_fields, + }) + } +} + +pub struct XCMBenchmarkAPIFields { + pub assets: Ident, + pub asset_manager: Ident, + pub asset_type: Ident, + pub runtime_origin: Ident, + pub relay_location: Ident, + pub parachain_system: Ident, + pub existential_deposit: Ident, + pub asset_id: Ident, + pub xcm_config: Ident, + pub account_id: Ident, + pub cents: Ident, + pub fee_asset_id: Ident, + pub transaction_byte_fee: Ident, +} + +impl TryFrom<&[Item]> for XCMBenchmarkAPIFields { + type Error = &'static str; + fn try_from(value: &[Item]) -> Result { + let mut assets = None; + let mut asset_manager = None; + let mut asset_type = None; + let mut runtime_origin = None; + let mut relay_location = None; + let mut parachain_system = None; + let mut existential_deposit = None; + let mut asset_id = None; + let mut xcm_config = None; + let mut account_id = None; + let mut cents = None; + let mut fee_asset_id = None; + let mut transaction_byte_fee = None; + + for item in value { + match item { + Item::Type(ty) => { + if ty.ident == "Assets" { + assets = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "AssetManager" { + asset_manager = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "AssetType" { + asset_type = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "RuntimeOrigin" { + runtime_origin = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "RelayLocation" { + relay_location = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "ParachainSystem" { + parachain_system = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "ExistentialDeposit" { + existential_deposit = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "AssetId" { + asset_id = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "XCMConfig" { + xcm_config = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "AccountId" { + account_id = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "Cents" { + cents = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "FeeAssetId" { + fee_asset_id = Some(fetch_ident(&ty.ty)) + } else if ty.ident == "TransactionByteFee" { + transaction_byte_fee = Some(fetch_ident(&ty.ty)) + } + } + _ => (), + } + } + + let assets = assets.ok_or("type `Assets` not specified, but required")?; + let asset_manager = + asset_manager.ok_or("type `AssetManager` not specified, but required")?; + let asset_type = asset_type.ok_or("type `AssetType` not specified, but required")?; + let runtime_origin = + runtime_origin.ok_or("type `RuntimeOrigin` not specified, but required")?; + let relay_location = + relay_location.ok_or("type `RelayLocation` not specified, but required")?; + let parachain_system = + parachain_system.ok_or("type `ParachainSystem` not specified, but required")?; + let existential_deposit = + existential_deposit.ok_or("type `ExistentialDeposit` not specified, but required")?; + let asset_id = asset_id.ok_or("type `AssetId` not specified, but required")?; + let xcm_config = xcm_config.ok_or("type `XCMConfig` not specified, but required")?; + let account_id = account_id.ok_or("type `AccountId` not specified, but required")?; + let cents = cents.ok_or("type `Cents` not specified, but required")?; + let fee_asset_id = fee_asset_id.ok_or("type `FeeAssetId` not specified, but required")?; + let transaction_byte_fee = + transaction_byte_fee.ok_or("type `TransactionByteFee` not specified, but required")?; + + Ok(XCMBenchmarkAPIFields { + assets, + asset_manager, + asset_type, + runtime_origin, + relay_location, + parachain_system, + existential_deposit, + asset_id, + xcm_config, + account_id, + cents, + fee_asset_id, + transaction_byte_fee, + }) + } +} + +pub fn construct_benchmarking_api( + consensus_benchmarking: bool, + runtime: &Ident, + api_fields: BenchmarkAPIFields, +) -> proc_macro2::TokenStream { let mut xcm_dispatch = quote! {}; let mut xcm_metadata = quote! {}; let mut consensus_dispatch = quote! {}; let mut consensus_metadata = quote! {}; - if state.consensus { - consensus_dispatch = construct_consensus_dispatch_benchmarking(); + if consensus_benchmarking { + consensus_dispatch = construct_consensus_dispatch_benchmarking(runtime); consensus_metadata = construct_consensus_metadata_benchmarking(); } - if state.assets && state.xcm { + let BenchmarkAPIFields { + all_pallets_with_system, + xcm_fields, + } = api_fields; + + if let Some(XCMBenchmarkAPIFields { + assets, + asset_manager, + asset_type, + runtime_origin, + relay_location, + parachain_system, + existential_deposit, + asset_id, + xcm_config, + account_id, + cents, + fee_asset_id, + transaction_byte_fee, + }) = xcm_fields + { xcm_metadata = construct_xcm_metadata_benchmarking(); - xcm_dispatch = construct_xcm_dispatch_benchmarking(); + xcm_dispatch = construct_xcm_dispatch_benchmarking( + runtime, + assets, + asset_manager, + asset_type, + runtime_origin, + relay_location, + parachain_system, + existential_deposit, + asset_id, + xcm_config, + account_id, + cents, + fee_asset_id, + transaction_byte_fee, + ); } quote! { #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { + impl frame_benchmarking::Benchmark for #runtime { fn benchmark_metadata(extra: bool) -> ( Vec, Vec, @@ -37,12 +220,10 @@ pub fn construct_benchmarking_api(state: AbstractionState) -> proc_macro2::Token #xcm_metadata #consensus_metadata - use super::*; - let mut list = Vec::::new(); list_benchmarks!(list, extra); - let storage_info = AllPalletsWithSystem::storage_info(); + let storage_info = #all_pallets_with_system::storage_info(); (list, storage_info) } @@ -52,13 +233,11 @@ pub fn construct_benchmarking_api(state: AbstractionState) -> proc_macro2::Token use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; use frame_system_benchmarking::Pallet as SystemBench; - use super::{*, types::*, configs::*, constants::currency::CENTS}; - #xcm_dispatch #consensus_dispatch use frame_support::traits::WhitelistedStorageKeys; - let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); + let whitelist = #all_pallets_with_system::whitelisted_storage_keys(); let mut batches = Vec::::new(); let params = (&config, &whitelist); @@ -77,10 +256,10 @@ fn construct_consensus_metadata_benchmarking() -> proc_macro2::TokenStream { } } -fn construct_consensus_dispatch_benchmarking() -> proc_macro2::TokenStream { +fn construct_consensus_dispatch_benchmarking(runtime: &Ident) -> proc_macro2::TokenStream { quote! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - impl cumulus_pallet_session_benchmarking::Config for Runtime {} + impl cumulus_pallet_session_benchmarking::Config for #runtime {} } } @@ -90,31 +269,49 @@ fn construct_xcm_metadata_benchmarking() -> proc_macro2::TokenStream { } } -// TODO: think how this should change if AssetManager is included -fn construct_xcm_dispatch_benchmarking() -> proc_macro2::TokenStream { +fn construct_xcm_dispatch_benchmarking( + runtime: &Ident, + assets: Ident, + asset_manager: Ident, + asset_type: Ident, + runtime_origin: Ident, + relay_location: Ident, + parachain_system: Ident, + existential_deposit: Ident, + asset_id: Ident, + xcm_config: Ident, + account_id: Ident, + cents: Ident, + fee_asset_id: Ident, + transaction_byte_fee: Ident, +) -> proc_macro2::TokenStream { quote! { use cumulus_primitives_core::ParaId; use frame_support::parameter_types; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + use xcm::latest::prelude::{Asset, AssetId as XcmAssetId, Assets as AssetList, Fungible, Location, Parachain, Parent, ParentThen, PalletInstance, GeneralIndex}; + parameter_types! { pub const RandomParaId: ParaId = ParaId::new(43211234); pub ExistentialDepositAsset: Option = Some(( - RelayLocation::get(), - ExistentialDeposit::get() + #relay_location::get(), + #existential_deposit::get() ).into()); /// The base fee for the message delivery fees. Kusama is based for the reference. - pub const ToParentBaseDeliveryFee: u128 = CENTS.saturating_mul(3); + pub const ToParentBaseDeliveryFee: u128 = #cents.saturating_mul(3); + pub const InitialTransferAssetAmount: u128 = 4001070000100; } + pub type PriceForParentDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< - FeeAssetId, + #fee_asset_id, ToParentBaseDeliveryFee, - TransactionByteFee, - ParachainSystem, + #transaction_byte_fee, + #parachain_system, >; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - use xcm::latest::prelude::{Asset, AssetId, Assets as AssetList, Fungible, Location, Parachain, Parent, ParentThen, PalletInstance, GeneralIndex}; - impl pallet_xcm::benchmarking::Config for Runtime { + + impl pallet_xcm::benchmarking::Config for #runtime { type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, + #xcm_config, ExistentialDepositAsset, PriceForParentDelivery, >; @@ -129,30 +326,61 @@ fn construct_xcm_dispatch_benchmarking() -> proc_macro2::TokenStream { fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { use frame_support::traits::PalletInfoAccess; - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - RandomParaId::get().into() + use xcm_primitives::AssetTypeGetter; + use frame_system::RawOrigin; + + // set up fee asset + let fee_location = #relay_location::get(); + let who: #account_id = frame_benchmarking::whitelisted_caller(); + + let Some(location_v3) = xcm::v3::Location::try_from(fee_location.clone()).ok() else { + return None; + }; + let asset_type = #asset_type::Xcm(location_v3); + + let local_asset_id: #asset_id = asset_type.clone().into(); + let manager_id = #asset_manager::account_id(); + let _ = #assets::force_create(#runtime_origin::root(), local_asset_id.clone().into(), sp_runtime::MultiAddress::Id(manager_id.clone()), true, 1); + let _ = #assets::mint( + RawOrigin::Signed(manager_id.clone()).into(), + local_asset_id.into(), + sp_runtime::MultiAddress::Id(who), + InitialTransferAssetAmount::get(), ); - let balance = 3001070000000; - let who = frame_benchmarking::whitelisted_caller(); - let _ = - >::make_free_balance_be(&who, balance); + #asset_manager::set_asset_type_asset_id(asset_type.clone(), local_asset_id.into()); - let asset_amount: u128 = 10u128; - let initial_asset_amount: u128 = asset_amount * 10; + // open a mock parachain channel + #parachain_system::open_outbound_hrmp_channel_for_benchmarks_or_tests( + RandomParaId::get().into() + ); + // set up transfer asset + let initial_asset_amount: u128 = InitialTransferAssetAmount::get(); let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< - Runtime, + #runtime, () >(true, initial_asset_amount); - let asset_id_u32: u32 = asset_id.into(); + let asset_id_u128: u128 = asset_id.into(); + let self_reserve = Location { + parents: 0, + interior: [ + PalletInstance(<#assets as PalletInfoAccess>::index() as u8), GeneralIndex(asset_id_u128) + ].into() + }; + + let Some(location_v3) = xcm::v3::Location::try_from(self_reserve.clone()).ok() else { + return None; + }; + let asset_type = #asset_type::Xcm(location_v3); + #asset_manager::set_asset_type_asset_id(asset_type.clone(), asset_id_u128); - let location = Location {parents: 0, interior: (PalletInstance(::index() as u8), GeneralIndex(asset_id_u32 as u128)).into()}; + let asset = Asset { + fun: Fungible(#existential_deposit::get()), + id: XcmAssetId(self_reserve.into()) + }.into(); Some(( - Asset { - fun: Fungible(ExistentialDeposit::get()), - id: AssetId(location.into()) - }.into(), + asset, ParentThen(Parachain(RandomParaId::get().into()).into()).into(), )) } @@ -160,55 +388,69 @@ fn construct_xcm_dispatch_benchmarking() -> proc_macro2::TokenStream { fn set_up_complex_asset_transfer( ) -> Option<(AssetList, u32, Location, Box)> { use frame_support::traits::PalletInfoAccess; + use xcm_primitives::AssetTypeGetter; // set up local asset - let asset_amount: u128 = 10u128; let initial_asset_amount: u128 = 1000000011; + let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< - Runtime, + #runtime, () >(true, initial_asset_amount); - let asset_id_u32: u32 = asset_id.into(); + + let asset_id_u128: u128 = asset_id.into(); let self_reserve = Location { parents:0, interior: [ - PalletInstance(::index() as u8), GeneralIndex(asset_id_u32 as u128) + PalletInstance(<#assets as PalletInfoAccess>::index() as u8), GeneralIndex(asset_id_u128) ].into() }; + let Some(location_v3) = xcm::v3::Location::try_from(self_reserve.clone()).ok() else { + return None; + }; + let asset_type = #asset_type::Xcm(location_v3); + #asset_manager::set_asset_type_asset_id(asset_type.clone(), asset_id_u128); + let destination: xcm::v4::Location = Parent.into(); - let fee_amount: u128 = ::ExistentialDeposit::get(); + // set up fee asset + let fee_amount: u128 = <#runtime as pallet_balances::Config>::ExistentialDeposit::get(); + let asset_amount: u128 = 10; let fee_asset: Asset = (self_reserve.clone(), fee_amount).into(); - - // Give some multiple of transferred amount - let balance = fee_amount * 1000; - let who = frame_benchmarking::whitelisted_caller(); - let _ = - >::make_free_balance_be(&who, balance); - - // verify initial balance - assert_eq!(Balances::free_balance(&who), balance); let transfer_asset: Asset = (self_reserve.clone(), asset_amount).into(); let assets: cumulus_primitives_core::Assets = vec![fee_asset.clone(), transfer_asset].into(); let fee_index: u32 = 0; + let who = frame_benchmarking::whitelisted_caller(); + let verify: Box = Box::new(move || { // verify balance after transfer, decreased by // transferred amount (and delivery fees) - assert!(Assets::balance(asset_id_u32, &who) <= initial_asset_amount - fee_amount); + assert!(#assets::balance(asset_id_u128, &who) <= initial_asset_amount - fee_amount); }); Some((assets, fee_index, destination, verify)) } fn get_asset() -> Asset { - use frame_support::traits::PalletInfoAccess; - Asset { - id: AssetId((Location {parents: 0, interior: (PalletInstance(::index() as u8), GeneralIndex(1)).into()}).into()), - fun: Fungible(ExistentialDeposit::get()), - } + use xcm_primitives::AssetTypeGetter; + let location = Location::parent(); + let asset_id = XcmAssetId(location.clone()); + let asset = Asset { + id: asset_id.clone(), + fun: Fungible(#existential_deposit::get()), + }; + let Some(location_v3) = xcm::v3::Location::try_from(location).ok() else { + return asset; + }; + let asset_type = #asset_type::Xcm(location_v3); + let local_asset_id: #asset_id = asset_type.clone().into(); + let manager_id = #asset_manager::account_id(); + let _ = #assets::force_create(#runtime_origin::root(), local_asset_id.clone().into(), sp_runtime::MultiAddress::Id(manager_id), true, 1); + #asset_manager::set_asset_type_asset_id(asset_type.clone(), local_asset_id); + asset } } } diff --git a/procedural/src/apis/consensus.rs b/procedural/src/apis/consensus.rs index 64ff170..863c3aa 100644 --- a/procedural/src/apis/consensus.rs +++ b/procedural/src/apis/consensus.rs @@ -45,26 +45,26 @@ impl TryFrom<&[Item]> for ConsensusAPIFields { if ty.ident == "SlotDuration" { slot_duration = Some(fetch_ident(&typ)) } else if ty.ident == "ConsensusHook" { - slot_duration = Some(fetch_ident(&typ)) + consensus_hook = Some(fetch_ident(&typ)) } } _ => (), } } - let session_keys = session_keys.ok_or("type SessionKeys` not specified, but required")?; + let session_keys = session_keys.ok_or("type `SessionKeys` not specified, but required")?; #[cfg(not(feature = "async-backing"))] { - let aura = aura.ok_or("type Aura` not specified, but required")?; + let aura = aura.ok_or("type `Aura` not specified, but required")?; Ok(ConsensusAPIFields { session_keys, aura }) } #[cfg(feature = "async-backing")] { let slot_duration = - slot_duration.ok_or("type SlotDuration` not specified, but required")?; + slot_duration.ok_or("type `SlotDuration` not specified, but required")?; let consensus_hook = - consensus_hook.ok_or("type SlotDuration` not specified, but required")?; + consensus_hook.ok_or("type `ConsensusHook` not specified, but required")?; Ok(ConsensusAPIFields { session_keys, slot_duration, @@ -84,14 +84,16 @@ pub fn consensus_apis( ) -> TokenStream { #[cfg(feature = "async-backing")] let slot_duration = quote! { - return sp_consensus_aura::SlotDuration::from_millis(<#api_ident as SystemAPI>::SLOT_DURATION); + return sp_consensus_aura::SlotDuration::from_millis(#slot_duration); }; #[cfg(not(feature = "async-backing"))] let slot_duration = quote! { sp_consensus_aura::SlotDuration::from_millis(#aura::slot_duration()) }; - let res = quote! { + let mut res = quote! {}; + + res.extend(quote! { impl sp_consensus_aura::AuraApi<#block, AuraId> for #runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { #slot_duration @@ -111,7 +113,7 @@ pub fn consensus_apis( #session_keys::decode_into_raw_public_keys(&encoded) } } - }; + }); #[cfg(feature = "async-backing")] res.extend(quote! { impl cumulus_primitives_aura::AuraUnincludedSegmentApi<#block> for #runtime { diff --git a/procedural/src/construct_runtime.rs b/procedural/src/construct_runtime.rs index 4fdec7a..9e5ac78 100644 --- a/procedural/src/construct_runtime.rs +++ b/procedural/src/construct_runtime.rs @@ -1,4 +1,4 @@ -use crate::models::Abstractions; +use crate::models::ConstructAbstractions; use proc_macro::TokenStream; use proc_macro2::{Literal, Span}; use quote::quote; @@ -57,10 +57,10 @@ fn parse_abstraction( item: ItemStruct, index: &mut u32, ) -> (proc_macro2::TokenStream, Option) { - let abstraction_name = Abstractions::try_from(item).expect("Wrong Struct"); + let abstraction_name = ConstructAbstractions::try_from(item).expect("Wrong Struct"); match abstraction_name { - Abstractions::System => ( + ConstructAbstractions::System => ( construct_system(index), Some(quote! { cumulus_pallet_parachain_system::register_validate_block! { @@ -69,11 +69,11 @@ fn parse_abstraction( } }), ), - Abstractions::Assets => (construct_assets(index), None), - Abstractions::Consensus => (construct_consensus(index), None), - Abstractions::Governance => (construct_governance(index), None), - Abstractions::XCM => (construct_xcm(index), None), - Abstractions::EVM => (construct_evm(index), None), + ConstructAbstractions::Assets => (construct_assets(index), None), + ConstructAbstractions::Consensus => (construct_consensus(index), None), + ConstructAbstractions::Governance => (construct_governance(index), None), + ConstructAbstractions::XCM => (construct_xcm(index), None), + ConstructAbstractions::EVM => (construct_evm(index), None), } } diff --git a/procedural/src/models.rs b/procedural/src/models.rs index daaccdc..9725843 100644 --- a/procedural/src/models.rs +++ b/procedural/src/models.rs @@ -1,7 +1,7 @@ use proc_macro2::Ident; use syn::ItemStruct; -pub enum Abstractions { +pub enum ConstructAbstractions { Assets, XCM, EVM, @@ -16,7 +16,7 @@ pub enum ConversionError { NoAbstractionAttribute, } -impl TryFrom for Abstractions { +impl TryFrom for ConstructAbstractions { type Error = ConversionError; fn try_from(value: ItemStruct) -> Result { let is_pallet = value.attrs.iter().any(|f| { @@ -32,25 +32,52 @@ impl TryFrom for Abstractions { return Err(ConversionError::NoAbstractionAttribute); } - Abstractions::try_from(value.ident) + ConstructAbstractions::try_from(value.ident) } } -impl TryFrom for Abstractions { +impl TryFrom for ConstructAbstractions { type Error = ConversionError; fn try_from(value: Ident) -> Result { if "Assets".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::Assets) + Ok(ConstructAbstractions::Assets) } else if "XCM".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::XCM) + Ok(ConstructAbstractions::XCM) } else if "EVM".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::EVM) + Ok(ConstructAbstractions::EVM) } else if "System".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::System) + Ok(ConstructAbstractions::System) } else if "Governance".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::Governance) + Ok(ConstructAbstractions::Governance) } else if "Consensus".eq_ignore_ascii_case(&value.to_string()) { - Ok(Abstractions::Consensus) + Ok(ConstructAbstractions::Consensus) + } else { + Err(ConversionError::UnknownAbstraction) + } + } +} + +pub enum APIAbstractions { + Benchmarks, + System, + EVM, + Consensus, + Assets, +} + +impl TryFrom for APIAbstractions { + type Error = ConversionError; + fn try_from(value: Ident) -> Result { + if "Benchmarks".eq_ignore_ascii_case(&value.to_string()) { + Ok(APIAbstractions::Benchmarks) + } else if "Assets".eq_ignore_ascii_case(&value.to_string()) { + Ok(APIAbstractions::Assets) + } else if "EVM".eq_ignore_ascii_case(&value.to_string()) { + Ok(APIAbstractions::EVM) + } else if "System".eq_ignore_ascii_case(&value.to_string()) { + Ok(APIAbstractions::System) + } else if "Consensus".eq_ignore_ascii_case(&value.to_string()) { + Ok(APIAbstractions::Consensus) } else { Err(ConversionError::UnknownAbstraction) } diff --git a/procedural/src/runtime_apis.rs b/procedural/src/runtime_apis.rs index 5f937b5..d967f98 100644 --- a/procedural/src/runtime_apis.rs +++ b/procedural/src/runtime_apis.rs @@ -1,9 +1,9 @@ use crate::{ apis::{ - self, construct_benchmarking_api, fetch_ident, AbstractionState, AssetAPIFields, + self, fetch_ident, AbstractionState, AssetAPIFields, BenchmarkAPIFields, ConsensusAPIFields, EVMAPIFields, SystemAPIFields, }, - models::Abstractions, + models::APIAbstractions, }; use core::panic; use proc_macro::TokenStream; @@ -34,13 +34,13 @@ pub fn impl_openzeppelin_runtime_apis(input: TokenStream) -> TokenStream { } Item::Mod(m) => { let is_abstraction = m.attrs.iter().any(|f| { - let Ok(path) = f.meta.require_path_only() else { - return false; - }; - let Ok(ident) = path.require_ident() else { - return false; - }; - ident == "abstraction" + let Ok(path) = f.meta.require_path_only() else { + return false; + }; + let Ok(ident) = path.require_ident() else { + return false; + }; + ident == "abstraction" }); if is_abstraction { abstractions.push(m) @@ -71,7 +71,15 @@ pub fn impl_openzeppelin_runtime_apis(input: TokenStream) -> TokenStream { )); } - let benchmarks = construct_benchmarking_api(state); + if let AbstractionState { + benchmark_fields: Some(fields), + consensus, + } = state + { + inner.extend(apis::construct_benchmarking_api( + consensus, &runtime, fields, + )); + } let expanded = quote! { use sp_api::impl_runtime_apis; @@ -92,8 +100,6 @@ pub fn impl_openzeppelin_runtime_apis(input: TokenStream) -> TokenStream { impl_runtime_apis! { #inner - - #benchmarks } }; @@ -106,13 +112,13 @@ fn construct_abstraction( runtime: &Ident, block: &Ident, ) -> proc_macro2::TokenStream { - let abstraction = Abstractions::try_from(item.ident).expect("Wrong Abstraction Struct"); + let abstraction = APIAbstractions::try_from(item.ident).expect("Wrong Abstraction Struct"); let (_, content) = item .content .expect("`mod assets` does not have any content."); match abstraction { - Abstractions::EVM => { + APIAbstractions::EVM => { let EVMAPIFields { call, executive, @@ -121,9 +127,7 @@ fn construct_abstraction( apis::evm_apis(runtime, block, &call, &executive, ðereum) } - Abstractions::Assets => { - state.assets = true; - + APIAbstractions::Assets => { let AssetAPIFields { transaction_payment, balance, @@ -133,9 +137,8 @@ fn construct_abstraction( apis::assets_apis(runtime, block, &transaction_payment, &balance, &call) } - Abstractions::Consensus => { - state.assets = true; - + APIAbstractions::Consensus => { + state.consensus = true; #[cfg(not(feature = "async-backing"))] { let ConsensusAPIFields { session_keys, aura } = @@ -160,7 +163,7 @@ fn construct_abstraction( ) } } - Abstractions::System => { + APIAbstractions::System => { let SystemAPIFields { executive, system, @@ -184,10 +187,13 @@ fn construct_abstraction( &genesis, ) } - Abstractions::XCM => { - state.xcm = true; + + APIAbstractions::Benchmarks => { + let api_fields = BenchmarkAPIFields::try_from(content.as_slice()) + .expect("Error while parsing benchmarking config"); + + state.benchmark_fields = Some(api_fields); quote! {} } - _ => quote! {}, } }