From d56731b0108d5eaf7e8d1f2779ecbd326cd867ea Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 16:00:55 +0300 Subject: [PATCH 1/9] benchmarks for pallet-bridge-asset-transfer --- Cargo.lock | 1 + pallets/parachain-system/src/lib.rs | 24 + .../pallets/bridge-assets-transfer/Cargo.toml | 4 +- .../src/benchmarking.rs | 889 +----------------- .../pallets/bridge-assets-transfer/src/lib.rs | 124 ++- .../bridge-assets-transfer/src/weights.rs | 53 +- .../runtimes/assets/statemine/Cargo.toml | 1 + .../runtimes/assets/statemine/src/lib.rs | 5 +- .../src/weights/bridge_assets_transfer.rs | 95 ++ .../assets/statemine/src/xcm_config.rs | 62 ++ scripts/benchmarks-ci.sh | 5 + 11 files changed, 328 insertions(+), 935 deletions(-) create mode 100644 parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs diff --git a/Cargo.lock b/Cargo.lock index 3f9b166ee2e..328b420be6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6049,6 +6049,7 @@ name = "pallet-bridge-assets-transfer" version = "0.1.0" dependencies = [ "cumulus-pallet-xcmp-queue", + "frame-benchmarking", "frame-support", "frame-system", "log", diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index 456ae5bf578..922a9b2a6f7 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -996,6 +996,30 @@ impl Pallet { pub fn set_custom_validation_head_data(head_data: Vec) { CustomValidationHeadData::::put(head_data); } + + /// Open HRMP channel for using it in benchmarks. + /// + /// The caller assumes that the pallet will accept regular outbound message to the sibling + /// `target_parachain` after this call. No other assumptions are made. + #[cfg(feature = "runtime-benchmarks")] + pub fn open_outbound_hrmp_channel_for_benchmarks(target_parachain: ParaId) { + RelevantMessagingState::::put(MessagingStateSnapshot { + dmq_mqc_head: Default::default(), + relay_dispatch_queue_size: Default::default(), + ingress_channels: Default::default(), + egress_channels: vec![( + target_parachain, + cumulus_primitives_core::AbridgedHrmpChannel { + max_capacity: 10, + max_total_size: 10_000_000_u32, + max_message_size: 10_000_000_u32, + msg_count: 10, + total_size: 10_000_000_u32, + mqc_head: None, + }, + )], + }) + } } pub struct ParachainSetCode(sp_std::marker::PhantomData); diff --git a/parachains/pallets/bridge-assets-transfer/Cargo.toml b/parachains/pallets/bridge-assets-transfer/Cargo.toml index e767c891892..a2eb9b82dce 100644 --- a/parachains/pallets/bridge-assets-transfer/Cargo.toml +++ b/parachains/pallets/bridge-assets-transfer/Cargo.toml @@ -17,6 +17,7 @@ log = { version = "0.4.14", default-features = false } # Substrate sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -45,7 +46,8 @@ std = [ "xcm-executor/std", ] runtime-benchmarks = [ - "sp-runtime/runtime-benchmarks", + "frame-benchmarking", "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs b/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs index e2e1579fcc9..07f495976e2 100644 --- a/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs +++ b/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs @@ -15,875 +15,54 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Alliance pallet benchmarking. +//! `BridgeAssetsTransfer` pallet benchmarks. -use sp_runtime::traits::{Bounded, Hash, StaticLookup}; -use sp_std::{ - cmp, - convert::{TryFrom, TryInto}, - mem::size_of, - prelude::*, -}; +use crate::{BenchmarkHelper, Bridges, Call, Config, Event, Pallet}; -use frame_benchmarking::{account, benchmarks_instance_pallet}; -use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; -use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; +use frame_benchmarking::{benchmarks, BenchmarkError}; +use frame_support::traits::EnsureOrigin; +use sp_std::prelude::*; -use super::{Call as AllianceCall, Pallet as Alliance, *}; - -const SEED: u32 = 0; - -const MAX_BYTES: u32 = 1_024; - -fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { - frame_system::Pallet::::assert_last_event(generic_event.into()); -} - -fn cid(input: impl AsRef<[u8]>) -> Cid { - use sha2::{Digest, Sha256}; - let mut hasher = Sha256::new(); - hasher.update(input); - let result = hasher.finalize(); - Cid::new_v0(&*result) -} - -fn rule(input: impl AsRef<[u8]>) -> Cid { - cid(input) -} - -fn announcement(input: impl AsRef<[u8]>) -> Cid { - cid(input) -} - -fn funded_account, I: 'static>(name: &'static str, index: u32) -> T::AccountId { - let account: T::AccountId = account(name, index, SEED); - T::Currency::make_free_balance_be(&account, BalanceOf::::max_value() / 100u8.into()); - account -} - -fn founder, I: 'static>(index: u32) -> T::AccountId { - funded_account::("founder", index) -} - -fn fellow, I: 'static>(index: u32) -> T::AccountId { - funded_account::("fellow", index) -} - -fn ally, I: 'static>(index: u32) -> T::AccountId { - funded_account::("ally", index) -} - -fn outsider, I: 'static>(index: u32) -> T::AccountId { - funded_account::("outsider", index) -} - -fn generate_unscrupulous_account, I: 'static>(index: u32) -> T::AccountId { - funded_account::("unscrupulous", index) -} - -fn set_members, I: 'static>() { - let founders: BoundedVec<_, T::MaxMembersCount> = - BoundedVec::try_from(vec![founder::(1), founder::(2)]).unwrap(); - Members::::insert(MemberRole::Founder, founders.clone()); - - let fellows: BoundedVec<_, T::MaxMembersCount> = - BoundedVec::try_from(vec![fellow::(1), fellow::(2)]).unwrap(); - fellows.iter().for_each(|who| { - T::Currency::reserve(&who, T::AllyDeposit::get()).unwrap(); - >::insert(&who, T::AllyDeposit::get()); - }); - Members::::insert(MemberRole::Fellow, fellows.clone()); - - let allies: BoundedVec<_, T::MaxMembersCount> = - BoundedVec::try_from(vec![ally::(1)]).unwrap(); - allies.iter().for_each(|who| { - T::Currency::reserve(&who, T::AllyDeposit::get()).unwrap(); - >::insert(&who, T::AllyDeposit::get()); - }); - Members::::insert(MemberRole::Ally, allies); - - T::InitializeMembers::initialize_members(&[founders.as_slice(), fellows.as_slice()].concat()); -} - -benchmarks_instance_pallet! { - // This tests when proposal is created and queued as "proposed" - propose_proposed { - let b in 1 .. MAX_BYTES; - let x in 2 .. T::MaxFounders::get(); - let y in 0 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - - let m = x + y; - - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let proposer = founders[0].clone(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - let threshold = m; - // Add previous proposals. - for i in 0 .. p - 1 { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal), - bytes_in_storage, - )?; - } - - let proposal: T::Proposal = AllianceCall::::set_rule { rule: rule(vec![p as u8; b as usize]) }.into(); - - }: propose(SystemOrigin::Signed(proposer.clone()), threshold, Box::new(proposal.clone()), bytes_in_storage) - verify { - // New proposal is recorded - let proposal_hash = T::Hashing::hash_of(&proposal); - assert_eq!(T::ProposalProvider::proposal_of(proposal_hash), Some(proposal)); - } - - vote { - // We choose 5 (3 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 3 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - - let m = x + y; - - let p = T::MaxProposals::get(); - let b = MAX_BYTES; - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let proposer = founders[0].clone(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - // Threshold is 1 less than the number of members so that one person can vote nay - let threshold = m - 1; - - // Add previous proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal.clone()), - b, - )?; - last_hash = T::Hashing::hash_of(&proposal); - } - - let index = p - 1; - // Have almost everyone vote aye on last proposal, while keeping it from passing. - for j in 0 .. m - 3 { - let voter = &members[j as usize]; - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - } - - let voter = members[m as usize - 3].clone(); - // Voter votes aye without resolving the vote. - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - - // Voter switches vote to nay, but does not kill the vote, just updates + inserts - let approve = false; - - // Whitelist voter account from further DB operations. - let voter_key = frame_system::Account::::hashed_key_for(&voter); - frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: _(SystemOrigin::Signed(voter), last_hash.clone(), index, approve) - verify { - } - - veto { - let p in 1 .. T::MaxProposals::get(); - - let m = 3; - let b = MAX_BYTES; - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. m).map(founder::).collect::>(); - let vetor = founders[0].clone(); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - vec![], - vec![], - )?; - - // Threshold is one less than total members so that two nays will disapprove the vote - let threshold = m - 1; - - // Add proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(vetor.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - } - - }: _(SystemOrigin::Signed(vetor), last_hash.clone()) - verify { - // The proposal is removed - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - - close_early_disapproved { - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - - let m = x + y; - - let bytes = 100; - let bytes_in_storage = bytes + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - let proposer = members[0].clone(); - let voter = members[1].clone(); - - // Threshold is total members so that one nay will disapprove the vote - let threshold = m; - - // Add previous proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; bytes as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); - } - - let index = p - 1; - // Have most everyone vote aye on last proposal, while keeping it from passing. - for j in 2 .. m - 1 { - let voter = &members[j as usize]; - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - } - - // Voter votes aye without resolving the vote. - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - - // Voter switches vote to nay, which kills the vote - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - false, - )?; - - // Whitelist voter account from further DB operations. - let voter_key = frame_system::Account::::hashed_key_for(&voter); - frame_benchmarking::benchmarking::add_to_whitelist(voter_key.into()); - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - - close_early_approved { - let b in 1 .. MAX_BYTES; - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - - let m = x + y; - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - let proposer = members[0].clone(); - let voter = members[1].clone(); - - // Threshold is 2 so any two ayes will approve the vote - let threshold = 2; - - // Add previous proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); - } - - let index = p - 1; - // Caller switches vote to nay on their own proposal, allowing them to be the deciding approval vote - Alliance::::vote( - SystemOrigin::Signed(proposer.clone()).into(), - last_hash.clone(), - index, - false, - )?; - - // Have almost everyone vote nay on last proposal, while keeping it from failing. - for j in 2 .. m - 1 { - let voter = &members[j as usize]; - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - false, - )?; - } - - // Member zero is the first aye - Alliance::::vote( - SystemOrigin::Signed(members[0].clone()).into(), - last_hash.clone(), - index, - true, - )?; - - let voter = members[1].clone(); - // Caller switches vote to aye, which passes the vote - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - - close_disapproved { - // We choose 2 (2 founders / 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - - let m = x + y; - - let bytes = 100; - let bytes_in_storage = bytes + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - let proposer = members[0].clone(); - let voter = members[1].clone(); - - // Threshold is one less than total members so that two nays will disapprove the vote - let threshold = m - 1; - - // Add proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; bytes as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); - } - - let index = p - 1; - // Have almost everyone vote aye on last proposal, while keeping it from passing. - // A few abstainers will be the nay votes needed to fail the vote. - for j in 2 .. m - 1 { - let voter = &members[j as usize]; - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - true, - )?; - } - - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - false, - )?; - - System::::set_block_number(T::BlockNumber::max_value()); - - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - - close_approved { - let b in 1 .. MAX_BYTES; - // We choose 4 (2 founders + 2 fellows) as a minimum so we always trigger a vote in the voting loop (`for j in ...`) - let x in 2 .. T::MaxFounders::get(); - let y in 2 .. T::MaxFellows::get(); - let p in 1 .. T::MaxProposals::get(); - - let m = x + y; - let bytes_in_storage = b + size_of::() as u32 + 32; - - // Construct `members`. - let founders = (0 .. x).map(founder::).collect::>(); - let fellows = (0 .. y).map(fellow::).collect::>(); - - let mut members = Vec::with_capacity(founders.len() + fellows.len()); - members.extend(founders.clone()); - members.extend(fellows.clone()); - - Alliance::::init_members( - SystemOrigin::Root.into(), - founders, - fellows, - vec![], - )?; - - let proposer = members[0].clone(); - let voter = members[1].clone(); - - // Threshold is two, so any two ayes will pass the vote - let threshold = 2; - - // Add proposals - let mut last_hash = T::Hash::default(); - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = AllianceCall::::set_rule { - rule: rule(vec![i as u8; b as usize]) - }.into(); - Alliance::::propose( - SystemOrigin::Signed(proposer.clone()).into(), - threshold, - Box::new(proposal.clone()), - bytes_in_storage, - )?; - last_hash = T::Hashing::hash_of(&proposal); - assert_eq!(T::ProposalProvider::proposal_of(last_hash), Some(proposal)); - } - - // The prime member votes aye, so abstentions default to aye. - Alliance::::vote( - SystemOrigin::Signed(proposer.clone()).into(), - last_hash.clone(), - p - 1, - true // Vote aye. - )?; - - let index = p - 1; - // Have almost everyone vote nay on last proposal, while keeping it from failing. - // A few abstainers will be the aye votes needed to pass the vote. - for j in 2 .. m - 1 { - let voter = &members[j as usize]; - Alliance::::vote( - SystemOrigin::Signed(voter.clone()).into(), - last_hash.clone(), - index, - false - )?; - } - - // caller is prime, prime already votes aye by creating the proposal - System::::set_block_number(T::BlockNumber::max_value()); - - }: close(SystemOrigin::Signed(voter), last_hash.clone(), index, Weight::MAX, bytes_in_storage) - verify { - // The last proposal is removed. - assert_eq!(T::ProposalProvider::proposal_of(last_hash), None); - } - - init_members { - // at least 1 founders - let x in 1 .. T::MaxFounders::get(); - let y in 0 .. T::MaxFellows::get(); - let z in 0 .. T::MaxAllies::get(); - - let mut founders = (0 .. x).map(founder::).collect::>(); - let mut fellows = (0 .. y).map(fellow::).collect::>(); - let mut allies = (0 .. z).map(ally::).collect::>(); - - }: _(SystemOrigin::Root, founders.clone(), fellows.clone(), allies.clone()) - verify { - founders.sort(); - fellows.sort(); - allies.sort(); - assert_last_event::(Event::MembersInitialized { - founders: founders.clone(), - fellows: fellows.clone(), - allies: allies.clone(), - }.into()); - assert_eq!(Alliance::::members(MemberRole::Founder), founders); - assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); - assert_eq!(Alliance::::members(MemberRole::Ally), allies); - } - - disband { - // at least 1 founders - let x in 1 .. T::MaxFounders::get() + T::MaxFellows::get(); - let y in 0 .. T::MaxAllies::get(); - let z in 0 .. T::MaxMembersCount::get() / 2; - - let voting_members = (0 .. x).map(founder::).collect::>(); - let allies = (0 .. y).map(ally::).collect::>(); - let witness = DisbandWitness{ - voting_members: x, - ally_members: y, - }; - - // setting the Alliance to disband on the benchmark call - Alliance::::init_members( - SystemOrigin::Root.into(), - voting_members.clone(), - vec![], - allies.clone(), - )?; - - // reserve deposits - let deposit = T::AllyDeposit::get(); - for member in voting_members.iter().chain(allies.iter()).take(z as usize) { - T::Currency::reserve(&member, deposit)?; - >::insert(&member, deposit); - } - - assert_eq!(Alliance::::voting_members_count(), x); - assert_eq!(Alliance::::ally_members_count(), y); - }: _(SystemOrigin::Root, witness) - verify { - assert_last_event::(Event::AllianceDisbanded { - voting_members: x, - ally_members: y, - unreserved: cmp::min(z, x + y), - }.into()); - - assert!(!Alliance::::is_initialized()); - } - - set_rule { - set_members::(); - - let rule = rule(b"hello world"); - - let call = Call::::set_rule { rule: rule.clone() }; - let origin = T::AdminOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert_eq!(Alliance::::rule(), Some(rule.clone())); - assert_last_event::(Event::NewRuleSet { rule }.into()); - } - - announce { - set_members::(); - - let announcement = announcement(b"hello world"); - - let call = Call::::announce { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } +benchmarks! { + transfer_asset_via_bridge { + let (bridged_network, bridge_config) = T::BenchmarkHelper::bridge_config(); + let (origin, assets, destination) = T::BenchmarkHelper::prepare_transfer(); + Bridges::::insert(bridged_network, bridge_config); + }: _(origin, Box::new(assets), Box::new(destination)) verify { - assert!(Alliance::::announcements().contains(&announcement)); - assert_last_event::(Event::Announced { announcement }.into()); + // we don't care about message hash here, just check that the transfer has been initiated + let actual_event = frame_system::Pallet::::events().pop().map(|r| r.event); + let expected_event: ::RuntimeEvent = Event::TransferInitiated(Default::default()).into(); + assert!(matches!(actual_event, Some(expected_event))); } - remove_announcement { - set_members::(); - - let announcement = announcement(b"hello world"); - let announcements: BoundedVec<_, T::MaxAnnouncementsCount> = BoundedVec::try_from(vec![announcement.clone()]).unwrap(); - Announcements::::put(announcements); - - let call = Call::::remove_announcement { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + add_bridge_config { + let origin = T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let (bridged_network, bridge_config) = T::BenchmarkHelper::bridge_config(); + }: _(origin, bridged_network, Box::new(bridge_config.clone())) verify { - assert!(Alliance::::announcements().is_empty()); - assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); + assert_eq!(Bridges::::get(bridged_network), Some(bridge_config)); } - join_alliance { - set_members::(); - - let outsider = outsider::(1); - assert!(!Alliance::::is_member(&outsider)); - assert_eq!(DepositOf::::get(&outsider), None); - }: _(SystemOrigin::Signed(outsider.clone())) + remove_bridge_config { + let origin = T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let (bridged_network, bridge_config) = T::BenchmarkHelper::bridge_config(); + Bridges::::insert(bridged_network, bridge_config); + }: _(origin, bridged_network) verify { - assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally - assert_eq!(DepositOf::::get(&outsider), Some(T::AllyDeposit::get())); // with a deposit - assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights - assert_last_event::(Event::NewAllyJoined { - ally: outsider, - nominator: None, - reserved: Some(T::AllyDeposit::get()) - }.into()); - } - - nominate_ally { - set_members::(); - - let founder1 = founder::(1); - assert!(Alliance::::is_member_of(&founder1, MemberRole::Founder)); - - let outsider = outsider::(1); - assert!(!Alliance::::is_member(&outsider)); - assert_eq!(DepositOf::::get(&outsider), None); - - let outsider_lookup = T::Lookup::unlookup(outsider.clone()); - }: _(SystemOrigin::Signed(founder1.clone()), outsider_lookup) - verify { - assert!(Alliance::::is_member_of(&outsider, MemberRole::Ally)); // outsider is now an ally - assert_eq!(DepositOf::::get(&outsider), None); // without a deposit - assert!(!Alliance::::has_voting_rights(&outsider)); // allies don't have voting rights - assert_last_event::(Event::NewAllyJoined { - ally: outsider, - nominator: Some(founder1), - reserved: None - }.into()); - } - - elevate_ally { - set_members::(); - - let ally1 = ally::(1); - assert!(Alliance::::is_ally(&ally1)); - - let ally1_lookup = T::Lookup::unlookup(ally1.clone()); - let call = Call::::elevate_ally { ally: ally1_lookup }; - let origin = T::MembershipManager::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert!(!Alliance::::is_ally(&ally1)); - assert!(Alliance::::is_fellow(&ally1)); - assert_last_event::(Event::AllyElevated { ally: ally1 }.into()); - } - - give_retirement_notice { - set_members::(); - let fellow2 = fellow::(2); - - assert!(Alliance::::is_fellow(&fellow2)); - }: _(SystemOrigin::Signed(fellow2.clone())) - verify { - assert!(Alliance::::is_member_of(&fellow2, MemberRole::Retiring)); - - assert_eq!( - RetiringMembers::::get(&fellow2), - Some(System::::block_number() + T::RetirementPeriod::get()) - ); - assert_last_event::( - Event::MemberRetirementPeriodStarted {member: fellow2}.into() - ); + assert_eq!(Bridges::::get(bridged_network), None); } - retire { - set_members::(); - - let fellow2 = fellow::(2); - assert!(Alliance::::is_fellow(&fellow2)); - - assert_eq!( - Alliance::::give_retirement_notice( - SystemOrigin::Signed(fellow2.clone()).into() - ), - Ok(()) - ); - System::::set_block_number(System::::block_number() + T::RetirementPeriod::get()); - - assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); - }: _(SystemOrigin::Signed(fellow2.clone())) - verify { - assert!(!Alliance::::is_member(&fellow2)); - assert_eq!(DepositOf::::get(&fellow2), None); - assert_last_event::(Event::MemberRetired { - member: fellow2, - unreserved: Some(T::AllyDeposit::get()) - }.into()); - } - - kick_member { - set_members::(); - - let fellow2 = fellow::(2); - assert!(Alliance::::is_member_of(&fellow2, MemberRole::Fellow)); - assert_eq!(DepositOf::::get(&fellow2), Some(T::AllyDeposit::get())); - - let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); - let call = Call::::kick_member { who: fellow2_lookup }; - let origin = T::MembershipManager::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert!(!Alliance::::is_member(&fellow2)); - assert_eq!(DepositOf::::get(&fellow2), None); - assert_last_event::(Event::MemberKicked { - member: fellow2, - slashed: Some(T::AllyDeposit::get()) - }.into()); - } - - add_unscrupulous_items { - let n in 0 .. T::MaxUnscrupulousItems::get(); - let l in 0 .. T::MaxWebsiteUrlLength::get(); - - set_members::(); - - let accounts = (0 .. n) - .map(|i| generate_unscrupulous_account::(i)) - .collect::>(); - let websites = (0 .. n).map(|i| -> BoundedVec { - BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() - }).collect::>(); - - let mut unscrupulous_list = Vec::with_capacity(accounts.len() + websites.len()); - unscrupulous_list.extend(accounts.into_iter().map(UnscrupulousItem::AccountId)); - unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); - - let call = Call::::add_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert_last_event::(Event::UnscrupulousItemAdded { items: unscrupulous_list }.into()); - } - - remove_unscrupulous_items { - let n in 0 .. T::MaxUnscrupulousItems::get(); - let l in 0 .. T::MaxWebsiteUrlLength::get(); - - set_members::(); - - let mut accounts = (0 .. n) - .map(|i| generate_unscrupulous_account::(i)) - .collect::>(); - accounts.sort(); - let accounts: BoundedVec<_, T::MaxUnscrupulousItems> = accounts.try_into().unwrap(); - UnscrupulousAccounts::::put(accounts.clone()); - - let mut websites = (0 .. n).map(|i| -> BoundedVec<_, T::MaxWebsiteUrlLength> - { BoundedVec::try_from(vec![i as u8; l as usize]).unwrap() }).collect::>(); - websites.sort(); - let websites: BoundedVec<_, T::MaxUnscrupulousItems> = websites.try_into().unwrap(); - UnscrupulousWebsites::::put(websites.clone()); - - let mut unscrupulous_list = Vec::with_capacity(accounts.len() + websites.len()); - unscrupulous_list.extend(accounts.into_iter().map(UnscrupulousItem::AccountId)); - unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); + update_bridge_config { + let origin = T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let (bridged_network, bridge_config) = T::BenchmarkHelper::bridge_config(); + Bridges::::insert(bridged_network, bridge_config); - let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + let fee = None; + }: _(origin, bridged_network, fee) verify { - assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); + assert_eq!(Bridges::::get(bridged_network).unwrap().fee, None); } - impl_benchmark_test_suite!(Alliance, crate::mock::new_bench_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::TestRuntime); } diff --git a/parachains/pallets/bridge-assets-transfer/src/lib.rs b/parachains/pallets/bridge-assets-transfer/src/lib.rs index ba87ae0d956..944275787c0 100644 --- a/parachains/pallets/bridge-assets-transfer/src/lib.rs +++ b/parachains/pallets/bridge-assets-transfer/src/lib.rs @@ -28,6 +28,8 @@ use sp_std::boxed::Box; pub use pallet::*; use xcm::prelude::*; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; pub mod weights; /// The log target of this pallet. @@ -67,6 +69,28 @@ pub mod pallet { #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); + /// Everything we need to run benchmarks. + #[cfg(feature = "runtime-benchmarks")] + pub trait BenchmarkHelper { + /// Returns proper bridge configuration, supported by the runtime. + /// + /// We expect that the XCM environment (`BridgeXcmSender`) has everything enabled + /// to support transfer to this destination **after** we our `prepare_transfer` call. + fn bridge_config() -> (NetworkId, BridgeConfig); + /// Prepare environment for assets transfer and return transfer origin and assets + /// to transfer. After this function is called, we expect `transfer_asset_via_bridge` + /// to succeed, so in proper environment, it should: + /// + /// - deposit enough funds (fee from `bridge_config()` and transferred assets) to the sender account; + /// + /// - ensure that the `BridgeXcmSender` is properly configured for the transfer; + /// + /// - be close to the worst possible scenario - i.e. if some account may need to be created during + /// the assets transfer, it should be created. If there are multiple bridges, the "worst possible" + /// (in terms of performance) bridge must be selected for the transfer. + fn prepare_transfer() -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation); + } + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. @@ -89,6 +113,10 @@ pub mod pallet { /// Required origin for asset transfer. If successful, it resolves to `MultiLocation`. type TransferOrigin: EnsureOrigin; + + /// Benchmarks helper. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelper; } /// Details of configured bridges which are allowed for transfer. @@ -390,7 +418,7 @@ pub mod pallet { } #[cfg(test)] -mod tests { +pub(crate) mod tests { use super::*; use crate as bridge_assets_transfer; use frame_support::traits::Currency; @@ -560,6 +588,62 @@ mod tests { (), >; + /// Bridge configuration we use in our tests. + fn test_bridge_config() -> (NetworkId, BridgeConfig) { + ( + Wococo, + BridgeConfig { + bridge_location: (Parent, Parachain(1013)).into(), + allowed_target_location: MultiLocation::new( + 2, + X2(GlobalConsensus(Wococo), Parachain(1000)), + ), + fee: None, + }, + ) + } + + /// Benchmarks helper. + #[cfg(feature = "runtime-benchmarks")] + pub struct TestBenchmarkHelper; + + #[cfg(feature = "runtime-benchmarks")] + impl BenchmarkHelper for TestBenchmarkHelper { + fn bridge_config() -> (NetworkId, BridgeConfig) { + test_bridge_config() + } + + fn prepare_transfer() -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation) { + let runtime_para_id = 1015; + let bridge_hub_para_id = 1013; + + // we'll need an HRMP channel between our parachain and bridge hub parachain + mock_open_hrmp_channel::( + runtime_para_id.into(), + bridge_hub_para_id.into(), + ); + + // sender account must have enough funds + let sender_account = account(1); + let _ = Balances::deposit_creating(&sender_account, ExistentialDeposit::get() * 10); + + // finally - prepare assets and destination + let assets = VersionedMultiAssets::V3( + MultiAsset { + fun: Fungible(ExistentialDeposit::get().into()), + id: Concrete(RelayLocation::get()), + } + .into(), + ); + let destination = VersionedMultiLocation::V3(MultiLocation::new( + 2, + X3(GlobalConsensus(Wococo), Parachain(1000), consensus_account(Wococo, 2)), + )); + + (RuntimeOrigin::signed(sender_account), assets, destination) + } + } + impl Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgeXcmSender = TestBridgeXcmSender; @@ -568,6 +652,8 @@ mod tests { type AssetTransactor = CurrencyTransactor; type AdminOrigin = EnsureRoot; type TransferOrigin = EnsureXcmOrigin; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = TestBenchmarkHelper; } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { @@ -598,14 +684,7 @@ mod tests { fn test_ensure_remote_destination() { new_test_ext().execute_with(|| { // insert bridge config - let bridge_config = BridgeConfig { - bridge_location: (Parent, Parachain(1013)).into(), - allowed_target_location: MultiLocation::new( - 2, - X2(GlobalConsensus(Wococo), Parachain(1000)), - ), - fee: None, - }; + let bridge_config = test_bridge_config(); assert_ok!(BridgeAssetsTransfer::add_bridge_config( RuntimeOrigin::root(), Wococo, @@ -683,14 +762,7 @@ mod tests { assert_ok!(BridgeAssetsTransfer::add_bridge_config( RuntimeOrigin::root(), bridged_network, - Box::new(BridgeConfig { - bridge_location: (Parent, Parachain(1013)).into(), - allowed_target_location: MultiLocation::new( - 2, - X2(GlobalConsensus(Wococo), Parachain(1000)) - ), - fee: None - }), + Box::new(test_bridge_config().1), )); let bridge_location = Bridges::::get(bridged_network) .expect("stored BridgeConfig for bridged_network") @@ -768,14 +840,7 @@ mod tests { #[test] fn test_bridge_config_management_works() { let bridged_network = Rococo; - let bridged_config = Box::new(BridgeConfig { - bridge_location: (Parent, Parachain(1013)).into(), - allowed_target_location: MultiLocation::new( - 2, - X2(GlobalConsensus(bridged_network), Parachain(1000)), - ), - fee: None, - }); + let bridged_config = Box::new(test_bridge_config().1); let dummy_xcm = Xcm(vec![]); let dummy_remote_interior_multilocation = X1(Parachain(1234)); @@ -797,14 +862,7 @@ mod tests { BridgeAssetsTransfer::add_bridge_config(RuntimeOrigin::root(), bridged_network, { let remote_network = Westend; assert_ne!(bridged_network, remote_network); - Box::new(BridgeConfig { - bridge_location: (Parent, Parachain(1013)).into(), - allowed_target_location: MultiLocation::new( - 2, - X2(GlobalConsensus(remote_network), Parachain(1000)), - ), - fee: None, - }) + Box::new(test_bridge_config().1) }), DispatchError::Module(ModuleError { index: 52, diff --git a/parachains/pallets/bridge-assets-transfer/src/weights.rs b/parachains/pallets/bridge-assets-transfer/src/weights.rs index 43ea26858ac..7fa0de7fc41 100644 --- a/parachains/pallets/bridge-assets-transfer/src/weights.rs +++ b/parachains/pallets/bridge-assets-transfer/src/weights.rs @@ -13,27 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_bridge_assets_transfer -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --pallet=pallet_alliance -// --chain=dev -// --output=./frame/alliance/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +//! Weights trait for the `pallet_bridge_assets_transfer` pallet. #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -42,36 +22,19 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; -/// Weight functions needed for pallet_alliance. +/// Weight functions needed for pallet_bridge_assets_transfer. pub trait WeightInfo { - fn transfer_asset_via_bridge(/* number of assets */) -> Weight; + /// Weight of the `transfer_asset_via_bridge` call. + fn transfer_asset_via_bridge() -> Weight; + /// Weight of the `add_bridge_config` call. fn add_bridge_config() -> Weight; + /// Weight of the `remove_bridge_config` call. fn remove_bridge_config() -> Weight; + /// Weight of the `update_bridge_config` call. fn update_bridge_config() -> Weight; } -/// Weights for pallet_alliance using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); - -impl WeightInfo for SubstrateWeight { - fn transfer_asset_via_bridge() -> Weight { - Weight::zero() - } - - fn add_bridge_config() -> Weight { - Weight::zero() - } - - fn remove_bridge_config() -> Weight { - Weight::zero() - } - - fn update_bridge_config() -> Weight { - Weight::zero() - } -} - -// For backwards compatibility and tests +// Zero weights to use in tests impl WeightInfo for () { fn transfer_asset_via_bridge() -> Weight { Weight::zero() diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 5a4a5441fb1..7f6845232d3 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -105,6 +105,7 @@ runtime-benchmarks = [ "pallet-xcm/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", diff --git a/parachains/runtimes/assets/statemine/src/lib.rs b/parachains/runtimes/assets/statemine/src/lib.rs index 3f31c9bd7f2..d2b00ebfa5f 100644 --- a/parachains/runtimes/assets/statemine/src/lib.rs +++ b/parachains/runtimes/assets/statemine/src/lib.rs @@ -626,10 +626,12 @@ impl pallet_bridge_assets_transfer::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgeXcmSender = BridgeXcmSender; type UniversalLocation = UniversalLocation; - type WeightInfo = pallet_bridge_assets_transfer::weights::SubstrateWeight; + type WeightInfo = (); type AssetTransactor = AssetTransactors; type AdminOrigin = AssetsForceOrigin; type TransferOrigin = EnsureXcmOrigin; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = xcm_config::BridgeAssetsTransferBenchmarksHelper; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -745,6 +747,7 @@ mod benches { // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] + [pallet_bridge_assets_transfer, BridgeAssetsTransfer] ); } diff --git a/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs b/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs new file mode 100644 index 00000000000..0019e3495fc --- /dev/null +++ b/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs @@ -0,0 +1,95 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + + +//! Autogenerated weights for `pallet_bridge_assets_transfer` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// target/debug/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_bridge_assets_transfer +// --chain=statemine-dev +// --header=./file_header.txt +// --output=./parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs +// --template=./templates/xcm-bench-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_bridge_assets_transfer`. +pub struct WeightInfo(PhantomData); +impl WeightInfo { + // Storage: ParachainInfo ParachainId (r:1 w:0) + // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: BridgeAssetsTransfer Bridges (r:1 w:0) + // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: PolkadotXcm SupportedVersion (r:1 w:0) + // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) + // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) + // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + // Storage: ParachainSystem RelevantMessagingState (r:1 w:0) + // Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) + // Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) + // Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) + // Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) + // Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) + pub(crate) fn transfer_asset_via_bridge() -> Weight { + Weight::from_ref_time(2_415_185_000 as u64) + .saturating_add(T::DbWeight::get().reads(9 as u64)) + .saturating_add(T::DbWeight::get().writes(5 as u64)) + } + // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + pub(crate) fn add_bridge_config() -> Weight { + Weight::from_ref_time(351_302_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + pub(crate) fn remove_bridge_config() -> Weight { + Weight::from_ref_time(372_143_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + pub(crate) fn update_bridge_config() -> Weight { + Weight::from_ref_time(405_395_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } +} diff --git a/parachains/runtimes/assets/statemine/src/xcm_config.rs b/parachains/runtimes/assets/statemine/src/xcm_config.rs index 09d3512fe03..e6dea4ba29e 100644 --- a/parachains/runtimes/assets/statemine/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemine/src/xcm_config.rs @@ -441,3 +441,65 @@ impl BenchmarkHelper for XcmBenchmarkHelper { /// Bridge router, which wraps and sends xcm to BridgeHub to be delivered to the different GlobalConsensus pub type BridgeXcmSender = UnpaidRemoteExporter; + +/// Benchmarks helper for over-bridge assets transfer pallet. +#[cfg(feature = "runtime-benchmarks")] +pub struct BridgeAssetsTransferBenchmarksHelper; + +impl BridgeAssetsTransferBenchmarksHelper { + /// Asset that we're transferring and paying fees in. + fn make_asset(fungible: u128) -> MultiAsset { + MultiAsset { fun: Fungible(fungible.into()), id: Concrete(KsmLocation::get()) } + } + + /// Parachain at the other side of the bridge that we're connected to. + fn allowed_target_location() -> MultiLocation { + MultiLocation::new(2, X2(GlobalConsensus(Polkadot), Parachain(1000))) + } + + /// Identifier of the sibling bridge-hub parachain. + fn bridge_hub_para_id() -> u32 { + 1013 + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_bridge_assets_transfer::BenchmarkHelper + for BridgeAssetsTransferBenchmarksHelper +{ + fn bridge_config() -> (NetworkId, pallet_bridge_assets_transfer::BridgeConfig) { + ( + Polkadot, + pallet_bridge_assets_transfer::BridgeConfig { + bridge_location: (Parent, Parachain(Self::bridge_hub_para_id())).into(), + allowed_target_location: Self::allowed_target_location(), + // TODO: right now `UnpaidRemoteExporter` is used to send XCM messages and it requires + // fee to be `None`. If we're going to change that (are we?), then we should replace + // this `None` with `Some(Self::make_asset(crate::ExistentialDeposit::get()))` + fee: None, + }, + ) + } + + fn prepare_transfer() -> (RuntimeOrigin, xcm::VersionedMultiAssets, xcm::VersionedMultiLocation) + { + use frame_support::traits::Currency; + + // our `BridgeXcmSender` assumes that the HRMP channel is opened between this + // parachain and the sibling bridge-hub parachain + cumulus_pallet_parachain_system::Pallet::::open_outbound_hrmp_channel_for_benchmarks( + Self::bridge_hub_para_id().into(), + ); + + // deposit enough funds to the sender account + let sender_account = AccountId::from([42u8; 32]); + let existential_deposit = crate::ExistentialDeposit::get(); + let _ = Balances::deposit_creating(&sender_account, existential_deposit * 10); + + // finaly - prepare assets and destination + let assets = xcm::VersionedMultiAssets::V3(Self::make_asset(existential_deposit).into()); + let destination = xcm::VersionedMultiLocation::V3(Self::allowed_target_location()); + + (RuntimeOrigin::signed(sender_account), assets, destination) + } +} diff --git a/scripts/benchmarks-ci.sh b/scripts/benchmarks-ci.sh index d4ad99d7bbe..c823f593c7c 100755 --- a/scripts/benchmarks-ci.sh +++ b/scripts/benchmarks-ci.sh @@ -25,6 +25,11 @@ if [[ $runtimeName == "statemint" ]] || [[ $runtimeName == "statemine" ]] || [[ pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible ) + + # bridge-assets-transfer pallet is only deployed at the Statemine + if [[ $runtimeName == "statemine" ]]; then + pallets+=("pallet_bridge_assets_transfer") + fi elif [[ $runtimeName == "collectives-polkadot" ]]; then pallets=( pallet_alliance From 0bd6afae8c01bc1078973c33af3404674349ab74 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 16:07:27 +0300 Subject: [PATCH 2/9] use proper template for pallet weights --- .../runtimes/assets/statemine/src/lib.rs | 2 +- .../src/weights/bridge_assets_transfer.rs | 107 ++++++++++-------- .../assets/statemine/src/weights/mod.rs | 1 + 3 files changed, 63 insertions(+), 47 deletions(-) diff --git a/parachains/runtimes/assets/statemine/src/lib.rs b/parachains/runtimes/assets/statemine/src/lib.rs index d2b00ebfa5f..277a223b072 100644 --- a/parachains/runtimes/assets/statemine/src/lib.rs +++ b/parachains/runtimes/assets/statemine/src/lib.rs @@ -626,7 +626,7 @@ impl pallet_bridge_assets_transfer::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgeXcmSender = BridgeXcmSender; type UniversalLocation = UniversalLocation; - type WeightInfo = (); + type WeightInfo = weights::bridge_assets_transfer::WeightInfo; type AssetTransactor = AssetTransactors; type AdminOrigin = AssetsForceOrigin; type TransferOrigin = EnsureXcmOrigin; diff --git a/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs b/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs index 0019e3495fc..28d4bff75bc 100644 --- a/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs +++ b/parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright 2021 Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . - //! Autogenerated weights for `pallet_bridge_assets_transfer` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -36,7 +36,6 @@ // --chain=statemine-dev // --header=./file_header.txt // --output=./parachains/runtimes/assets/statemine/src/weights/bridge_assets_transfer.rs -// --template=./templates/xcm-bench-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,51 +44,67 @@ use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for `pallet_bridge_assets_transfer`. +/// Weight functions for `pallet_bridge_assets_transfer`. pub struct WeightInfo(PhantomData); -impl WeightInfo { - // Storage: ParachainInfo ParachainId (r:1 w:0) - // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - // Storage: BridgeAssetsTransfer Bridges (r:1 w:0) - // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) - // Storage: System Account (r:2 w:2) - // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - // Storage: PolkadotXcm SupportedVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) - // Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) - // Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - // Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) - // Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - // Storage: ParachainSystem RelevantMessagingState (r:1 w:0) - // Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) - // Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) - // Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) - // Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) - pub(crate) fn transfer_asset_via_bridge() -> Weight { - Weight::from_ref_time(2_415_185_000 as u64) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) +impl pallet_bridge_assets_transfer::WeightInfo for WeightInfo { + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:0) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) + /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) + /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem RelevantMessagingState (r:1 w:0) + /// Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) + fn transfer_asset_via_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `17786` + // Minimum execution time: 2_415_358 nanoseconds. + Weight::from_parts(2_474_758_000, 17786) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) - // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) - pub(crate) fn add_bridge_config() -> Weight { - Weight::from_ref_time(351_302_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn add_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `4374` + // Minimum execution time: 345_841 nanoseconds. + Weight::from_parts(361_206_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) - // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) - pub(crate) fn remove_bridge_config() -> Weight { - Weight::from_ref_time(372_143_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn remove_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `131` + // Estimated: `4374` + // Minimum execution time: 367_373 nanoseconds. + Weight::from_parts(379_332_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: BridgeAssetsTransfer Bridges (r:1 w:1) - // Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) - pub(crate) fn update_bridge_config() -> Weight { - Weight::from_ref_time(405_395_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn update_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `131` + // Estimated: `4374` + // Minimum execution time: 385_827 nanoseconds. + Weight::from_parts(394_729_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/mod.rs b/parachains/runtimes/assets/statemine/src/weights/mod.rs index 5dd6ffd662e..66f73748f3b 100644 --- a/parachains/runtimes/assets/statemine/src/weights/mod.rs +++ b/parachains/runtimes/assets/statemine/src/weights/mod.rs @@ -1,4 +1,5 @@ pub mod block_weights; +pub mod bridge_assets_transfer; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; From a3642ce9cc3fd7c0aec124c67fdddf4ede85f168 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 16:15:15 +0300 Subject: [PATCH 3/9] fix test --- .../pallets/bridge-assets-transfer/src/lib.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/parachains/pallets/bridge-assets-transfer/src/lib.rs b/parachains/pallets/bridge-assets-transfer/src/lib.rs index 944275787c0..bb0690c1029 100644 --- a/parachains/pallets/bridge-assets-transfer/src/lib.rs +++ b/parachains/pallets/bridge-assets-transfer/src/lib.rs @@ -614,15 +614,6 @@ pub(crate) mod tests { } fn prepare_transfer() -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation) { - let runtime_para_id = 1015; - let bridge_hub_para_id = 1013; - - // we'll need an HRMP channel between our parachain and bridge hub parachain - mock_open_hrmp_channel::( - runtime_para_id.into(), - bridge_hub_para_id.into(), - ); - // sender account must have enough funds let sender_account = account(1); let _ = Balances::deposit_creating(&sender_account, ExistentialDeposit::get() * 10); @@ -684,7 +675,7 @@ pub(crate) mod tests { fn test_ensure_remote_destination() { new_test_ext().execute_with(|| { // insert bridge config - let bridge_config = test_bridge_config(); + let bridge_config = test_bridge_config().1; assert_ok!(BridgeAssetsTransfer::add_bridge_config( RuntimeOrigin::root(), Wococo, @@ -840,7 +831,14 @@ pub(crate) mod tests { #[test] fn test_bridge_config_management_works() { let bridged_network = Rococo; - let bridged_config = Box::new(test_bridge_config().1); + let bridged_config = Box::new(BridgeConfig { + bridge_location: (Parent, Parachain(1013)).into(), + allowed_target_location: MultiLocation::new( + 2, + X2(GlobalConsensus(bridged_network), Parachain(1000)), + ), + fee: None, + }); let dummy_xcm = Xcm(vec![]); let dummy_remote_interior_multilocation = X1(Parachain(1234)); From 04e0f8b260b4090df78ebc967864bd145d7b0890 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 16:53:21 +0300 Subject: [PATCH 4/9] fixing compialtion --- parachains/pallets/bridge-assets-transfer/src/lib.rs | 3 ++- parachains/runtimes/assets/statemine/src/xcm_config.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/parachains/pallets/bridge-assets-transfer/src/lib.rs b/parachains/pallets/bridge-assets-transfer/src/lib.rs index bb0690c1029..941ed8c95a8 100644 --- a/parachains/pallets/bridge-assets-transfer/src/lib.rs +++ b/parachains/pallets/bridge-assets-transfer/src/lib.rs @@ -57,8 +57,9 @@ impl From for (MultiLocation, Option) { #[frame_support::pallet] pub mod pallet { + pub use crate::weights::WeightInfo; + use super::*; - use crate::weights::WeightInfo; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use xcm::latest::Error as XcmError; diff --git a/parachains/runtimes/assets/statemine/src/xcm_config.rs b/parachains/runtimes/assets/statemine/src/xcm_config.rs index e6dea4ba29e..c70fb97e545 100644 --- a/parachains/runtimes/assets/statemine/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemine/src/xcm_config.rs @@ -446,6 +446,7 @@ pub type BridgeXcmSender = UnpaidRemoteExporter MultiAsset { From 637470d65730c5d2a85547d8475f811498f037d8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 17:26:19 +0300 Subject: [PATCH 5/9] fix (?) compilation warn/error in westmint --- parachains/runtimes/assets/westmint/src/xcm_config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parachains/runtimes/assets/westmint/src/xcm_config.rs b/parachains/runtimes/assets/westmint/src/xcm_config.rs index 7f09f8f5a24..be712c674b1 100644 --- a/parachains/runtimes/assets/westmint/src/xcm_config.rs +++ b/parachains/runtimes/assets/westmint/src/xcm_config.rs @@ -315,7 +315,7 @@ impl xcm_executor::Config for XcmConfig { // Westmint is acting _as_ a reserve location for WND and assets created under `pallet-assets`. // For WND, users must use teleport where allowed (e.g. with the Relay Chain). type IsReserve = - (ConcreteFungibleAssetsFromTrustedBridgedReserves); + ConcreteFungibleAssetsFromTrustedBridgedReserves; type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of WND type UniversalLocation = UniversalLocation; type Barrier = Barrier; From e35fabea59a02196740f4bcdc1a1aeebe234c0a1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 14 Mar 2023 18:21:29 +0300 Subject: [PATCH 6/9] weight limits in can_governance_call_xcm_transact_with_bridge_assets_transfer_configuration --- parachains/runtimes/assets/statemine/tests/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachains/runtimes/assets/statemine/tests/tests.rs b/parachains/runtimes/assets/statemine/tests/tests.rs index 13bea6268e3..c292a2e0fc3 100644 --- a/parachains/runtimes/assets/statemine/tests/tests.rs +++ b/parachains/runtimes/assets/statemine/tests/tests.rs @@ -451,7 +451,7 @@ fn test_send_xcm_transact_with_remark_with_event_works() { } #[test] -fn can_govornance_call_xcm_transact_with_bridge_assets_transfer_configuration() { +fn can_governance_call_xcm_transact_with_bridge_assets_transfer_configuration() { ExtBuilder::::default() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( @@ -491,7 +491,7 @@ fn can_govornance_call_xcm_transact_with_bridge_assets_transfer_configuration() UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Superuser, - require_weight_at_most: Weight::from_ref_time(1000000000), + require_weight_at_most: Weight::from_parts(2000000000, 2000000000), call: add_bridge_config.encode().into(), }, ]); @@ -501,7 +501,7 @@ fn can_govornance_call_xcm_transact_with_bridge_assets_transfer_configuration() // initialize bridge through governance-like let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - let weight_limit = Weight::from_ref_time(41666666666); + let weight_limit = Weight::from_parts(5000000000, 5000000000); let outcome = XcmExecutor::::execute_xcm(origin, xcm, hash, weight_limit); assert_eq!(outcome.ensure_complete(), Ok(())); From 89faece5109ca97d9c9325e74ffc5c84594c72a2 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 14 Mar 2023 18:15:30 +0000 Subject: [PATCH 7/9] ".git/.scripts/commands/bench/bench.sh" pallet statemine assets pallet_bridge_assets_transfer --- .../weights/pallet_bridge_assets_transfer.rs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs new file mode 100644 index 00000000000..afda48b1f4f --- /dev/null +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs @@ -0,0 +1,111 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +//! Autogenerated weights for `pallet_bridge_assets_transfer` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/polkadot-parachain +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/cumulus/.git/.artifacts/bench.json +// --pallet=pallet_bridge_assets_transfer +// --chain=statemine-dev +// --header=./file_header.txt +// --output=./parachains/runtimes/assets/statemine/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_bridge_assets_transfer`. +pub struct WeightInfo(PhantomData); +impl pallet_bridge_assets_transfer::WeightInfo for WeightInfo { + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:0) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: PolkadotXcm SupportedVersion (r:1 w:0) + /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: PolkadotXcm VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: PolkadotXcm VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: PolkadotXcm SafeXcmVersion (r:1 w:0) + /// Proof Skipped: PolkadotXcm SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainSystem RelevantMessagingState (r:1 w:0) + /// Proof Skipped: ParachainSystem RelevantMessagingState (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpStatus (r:1 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpStatus (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmpQueue OutboundXcmpMessages (r:0 w:1) + /// Proof Skipped: XcmpQueue OutboundXcmpMessages (max_values: None, max_size: None, mode: Measured) + fn transfer_asset_via_bridge() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `17786` + // Minimum execution time: 99_930 nanoseconds. + Weight::from_parts(101_075_000, 17786) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn add_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `4374` + // Minimum execution time: 13_023 nanoseconds. + Weight::from_parts(13_566_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn remove_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `131` + // Estimated: `4374` + // Minimum execution time: 12_459 nanoseconds. + Weight::from_parts(12_755_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: BridgeAssetsTransfer Bridges (r:1 w:1) + /// Proof: BridgeAssetsTransfer Bridges (max_values: None, max_size: Some(1899), added: 4374, mode: MaxEncodedLen) + fn update_bridge_config() -> Weight { + // Proof Size summary in bytes: + // Measured: `131` + // Estimated: `4374` + // Minimum execution time: 15_479 nanoseconds. + Weight::from_parts(15_821_000, 4374) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} From eb0fc0ad4a94dcd22c875eb90b0bb5ffe58f9191 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 14 Mar 2023 19:23:19 +0000 Subject: [PATCH 8/9] ".git/.scripts/commands/bench/bench.sh" pallet statemine assets pallet_bridge_assets_transfer --- .../src/weights/pallet_bridge_assets_transfer.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs index afda48b1f4f..d4e921fcbf1 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_bridge_assets_transfer.rs @@ -70,8 +70,8 @@ impl pallet_bridge_assets_transfer::WeightInfo for Weig // Proof Size summary in bytes: // Measured: `542` // Estimated: `17786` - // Minimum execution time: 99_930 nanoseconds. - Weight::from_parts(101_075_000, 17786) + // Minimum execution time: 99_958 nanoseconds. + Weight::from_parts(101_321_000, 17786) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -81,8 +81,8 @@ impl pallet_bridge_assets_transfer::WeightInfo for Weig // Proof Size summary in bytes: // Measured: `76` // Estimated: `4374` - // Minimum execution time: 13_023 nanoseconds. - Weight::from_parts(13_566_000, 4374) + // Minimum execution time: 13_133 nanoseconds. + Weight::from_parts(13_473_000, 4374) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -92,8 +92,8 @@ impl pallet_bridge_assets_transfer::WeightInfo for Weig // Proof Size summary in bytes: // Measured: `131` // Estimated: `4374` - // Minimum execution time: 12_459 nanoseconds. - Weight::from_parts(12_755_000, 4374) + // Minimum execution time: 12_449 nanoseconds. + Weight::from_parts(12_798_000, 4374) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -103,8 +103,8 @@ impl pallet_bridge_assets_transfer::WeightInfo for Weig // Proof Size summary in bytes: // Measured: `131` // Estimated: `4374` - // Minimum execution time: 15_479 nanoseconds. - Weight::from_parts(15_821_000, 4374) + // Minimum execution time: 21_405 nanoseconds. + Weight::from_parts(21_653_000, 4374) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } From 353833b56be8a5b218ef630f3531cd925cd6a7e7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 15 Mar 2023 10:19:20 +0300 Subject: [PATCH 9/9] add prototype for multiple assets benchmarking --- .../bridge-assets-transfer/src/benchmarking.rs | 6 +++++- .../pallets/bridge-assets-transfer/src/lib.rs | 17 ++++++++++++----- .../runtimes/assets/statemine/src/xcm_config.rs | 7 +++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs b/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs index 07f495976e2..0aee9e477c0 100644 --- a/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs +++ b/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs @@ -25,8 +25,12 @@ use sp_std::prelude::*; benchmarks! { transfer_asset_via_bridge { + // every asset has its own configuration and ledger, so there's a performance dependency + // TODO: add proper range after once pallet works with multiple assets + // (be sure to use "worst" of assets) + // let a in 1 .. 1; let (bridged_network, bridge_config) = T::BenchmarkHelper::bridge_config(); - let (origin, assets, destination) = T::BenchmarkHelper::prepare_transfer(); + let (origin, assets, destination) = T::BenchmarkHelper::prepare_transfer(1); Bridges::::insert(bridged_network, bridge_config); }: _(origin, Box::new(assets), Box::new(destination)) verify { diff --git a/parachains/pallets/bridge-assets-transfer/src/lib.rs b/parachains/pallets/bridge-assets-transfer/src/lib.rs index 941ed8c95a8..23b40529da5 100644 --- a/parachains/pallets/bridge-assets-transfer/src/lib.rs +++ b/parachains/pallets/bridge-assets-transfer/src/lib.rs @@ -89,7 +89,9 @@ pub mod pallet { /// - be close to the worst possible scenario - i.e. if some account may need to be created during /// the assets transfer, it should be created. If there are multiple bridges, the "worst possible" /// (in terms of performance) bridge must be selected for the transfer. - fn prepare_transfer() -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation); + fn prepare_transfer( + assets_count: u32, + ) -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation); } #[pallet::config] @@ -614,17 +616,22 @@ pub(crate) mod tests { test_bridge_config() } - fn prepare_transfer() -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation) { + fn prepare_transfer( + assets_count: u32, + ) -> (RuntimeOrigin, VersionedMultiAssets, VersionedMultiLocation) { // sender account must have enough funds let sender_account = account(1); - let _ = Balances::deposit_creating(&sender_account, ExistentialDeposit::get() * 10); + let total_deposit = ExistentialDeposit::get() * (1 + assets_count as u64); + let _ = Balances::deposit_creating(&sender_account, total_deposit); // finally - prepare assets and destination let assets = VersionedMultiAssets::V3( - MultiAsset { + std::iter::repeat(MultiAsset { fun: Fungible(ExistentialDeposit::get().into()), id: Concrete(RelayLocation::get()), - } + }) + .take(assets_count as usize) + .collect::>() .into(), ); let destination = VersionedMultiLocation::V3(MultiLocation::new( diff --git a/parachains/runtimes/assets/statemine/src/xcm_config.rs b/parachains/runtimes/assets/statemine/src/xcm_config.rs index c70fb97e545..0d46b7a0fc6 100644 --- a/parachains/runtimes/assets/statemine/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemine/src/xcm_config.rs @@ -482,10 +482,13 @@ impl pallet_bridge_assets_transfer::BenchmarkHelper ) } - fn prepare_transfer() -> (RuntimeOrigin, xcm::VersionedMultiAssets, xcm::VersionedMultiLocation) - { + fn prepare_transfer( + assets_count: u32, + ) -> (RuntimeOrigin, xcm::VersionedMultiAssets, xcm::VersionedMultiLocation) { use frame_support::traits::Currency; + assert_eq!(assets_count, 1, "Benchmarks needs to be fixed to support multiple assets"); + // our `BridgeXcmSender` assumes that the HRMP channel is opened between this // parachain and the sibling bridge-hub parachain cumulus_pallet_parachain_system::Pallet::::open_outbound_hrmp_channel_for_benchmarks(