From 39ba56492addf6e5bf27a136c9297aded30c3b95 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 14 Dec 2022 16:31:15 +0100 Subject: [PATCH] Init of pallet with `transfer_asset_via_bridge` call --- Cargo.lock | 34 +- .../pallets/bridge-assets-transfer/Cargo.toml | 10 +- .../src/benchmarking.rs | 889 ++++++++++++++++++ .../pallets/bridge-assets-transfer/src/lib.rs | 243 ++++- .../bridge-assets-transfer/src/weights.rs | 91 ++ .../runtimes/assets/statemine/Cargo.toml | 6 +- .../runtimes/assets/statemine/src/lib.rs | 8 +- .../assets/statemine/src/xcm_config.rs | 23 +- 8 files changed, 1241 insertions(+), 63 deletions(-) create mode 100644 parachains/pallets/bridge-assets-transfer/src/benchmarking.rs create mode 100644 parachains/pallets/bridge-assets-transfer/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 5cc63dd432..00bd69c68f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -713,22 +713,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "bridge-assets-transfer" -version = "0.1.0" -dependencies = [ - "frame-support", - "frame-system", - "log", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std", - "sp-version", - "xcm", - "xcm-builder", -] - [[package]] name = "bs58" version = "0.4.0" @@ -5501,6 +5485,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-bridge-assets-transfer" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", + "sp-version", + "xcm", + "xcm-builder", +] + [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" @@ -11533,7 +11533,6 @@ name = "statemine-runtime" version = "2.0.0" dependencies = [ "asset-test-utils", - "bridge-assets-transfer", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -11558,6 +11557,7 @@ dependencies = [ "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-bridge-assets-transfer", "pallet-collator-selection", "pallet-multisig", "pallet-proxy", diff --git a/parachains/pallets/bridge-assets-transfer/Cargo.toml b/parachains/pallets/bridge-assets-transfer/Cargo.toml index 08b0f58a21..0378309181 100644 --- a/parachains/pallets/bridge-assets-transfer/Cargo.toml +++ b/parachains/pallets/bridge-assets-transfer/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bridge-assets-transfer" +name = "pallet-bridge-assets-transfer" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" @@ -22,10 +22,10 @@ frame-system = { git = "https://github.com/paritytech/substrate", default-featur # Polkadot xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } +xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } [dev-dependencies] sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master" } [features] default = ["std"] @@ -37,4 +37,10 @@ std = [ "frame-support/std", "frame-system/std", "xcm/std", + "xcm-builder/std", ] +runtime-benchmarks = [ + "sp-runtime/runtime-benchmarks", + "frame-system/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 new file mode 100644 index 0000000000..e2e1579fcc --- /dev/null +++ b/parachains/pallets/bridge-assets-transfer/src/benchmarking.rs @@ -0,0 +1,889 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Alliance pallet benchmarking. + +use sp_runtime::traits::{Bounded, Hash, StaticLookup}; +use sp_std::{ + cmp, + convert::{TryFrom, TryInto}, + mem::size_of, + prelude::*, +}; + +use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; +use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; + +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)? } + verify { + assert!(Alliance::::announcements().contains(&announcement)); + assert_last_event::(Event::Announced { announcement }.into()); + } + + 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)? } + verify { + assert!(Alliance::::announcements().is_empty()); + assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); + } + + join_alliance { + set_members::(); + + let outsider = outsider::(1); + assert!(!Alliance::::is_member(&outsider)); + assert_eq!(DepositOf::::get(&outsider), None); + }: _(SystemOrigin::Signed(outsider.clone())) + 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() + ); + } + + 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)); + + let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; + let origin = T::AnnouncementOrigin::successful_origin(); + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); + } + + impl_benchmark_test_suite!(Alliance, crate::mock::new_bench_ext(), crate::mock::Test); +} diff --git a/parachains/pallets/bridge-assets-transfer/src/lib.rs b/parachains/pallets/bridge-assets-transfer/src/lib.rs index c4b3ecb48c..f99f13ad20 100644 --- a/parachains/pallets/bridge-assets-transfer/src/lib.rs +++ b/parachains/pallets/bridge-assets-transfer/src/lib.rs @@ -20,17 +20,39 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; + pub use pallet::*; use xcm::prelude::*; +pub mod weights; + /// The log target of this pallet. pub const LOG_TARGET: &str = "runtime::bridge-assets-transfer"; +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct BridgeConfig { + /// Contains location, which is able to bridge XCM messages to bridged network + bridge_location: MultiLocation, + /// Fee which could be needed to pay in `bridge_location` + fee: Option, +} + +impl From for (MultiLocation, Option) { + fn from(bridge_config: BridgeConfig) -> (MultiLocation, Option) { + (bridge_config.bridge_location, bridge_config.fee) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; + use crate::weights::WeightInfo; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use xcm_builder::ExporterFor; #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] @@ -45,16 +67,17 @@ pub mod pallet { /// XCM sender which sends messages to the BridgeHub type BridgeXcmSender: SendXcm; - // TODO: store as persistent and create add_bridge/remove_bridge - then we can have generic impl and dont need to hardcode NetworkId/ParaId in runtime - /// Configuration for supported bridged networks - type SupportedBridges: Get< - sp_std::prelude::Vec<(NetworkId, MultiLocation, Option)>, - >; - /// Runtime's universal location type UniversalLocation: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } + #[pallet::storage] + /// Details of configured bridges which are allowed for transfer. + pub(super) type Bridges = StorageMap<_, Blake2_128Concat, NetworkId, BridgeConfig>; + #[pallet::error] #[cfg_attr(test, derive(PartialEq))] pub enum Error { @@ -69,6 +92,13 @@ pub mod pallet { // TODO: add here xcm_hash? /// Transfer was successfully entered to the system (does not mean already delivered) TransferInitiated(XcmHash), + + /// New bridge configuration was added + BridgeAdded, + /// Bridge configuration was removed + BridgeRemoved, + /// Bridge configuration was updated + BridgeUpdated, } #[pallet::call] @@ -78,10 +108,8 @@ pub mod pallet { /// Parameters: /// /// * `assets`: - /// * `destination`: Different consensus location, where the assets will be deposited, e.g. Polkadot's Statemint: `X2(GlobalConsensus(NetworkId::Polkadot), Parachain(1000))` - /// - // TODO: correct weigth - #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + /// * `destination`: Different consensus location, where the assets will be deposited, e.g. Polkadot's Statemint: `2, X2(GlobalConsensus(NetworkId::Polkadot), Parachain(1000))` + #[pallet::weight(T::WeightInfo::transfer_asset_via_bridge())] pub fn transfer_asset_via_bridge( origin: OriginFor, assets: VersionedMultiAssets, @@ -135,6 +163,67 @@ pub mod pallet { Self::deposit_event(Event::TransferInitiated(xcm_hash)); Ok(()) } + + /// Adds new bridge configuration, which allows transfer to this `bridged_network`. + /// + /// Parameters: + /// + /// * `bridged_network`: Network where we want to allow transfer funds + /// * `bridge_config`: contains location for BridgeHub in our network + fee + #[pallet::weight(T::WeightInfo::add_bridge_config())] + pub fn add_bridge_config( + origin: OriginFor, + bridged_network: NetworkId, + bridge_config: BridgeConfig, + ) -> DispatchResult { + let _ = ensure_root(origin)?; + ensure!(!Bridges::::contains_key(bridged_network), Error::::InvalidConfiguration); + + Bridges::::insert(bridged_network, bridge_config); + Self::deposit_event(Event::BridgeAdded); + Ok(()) + } + + /// Remove bridge configuration for specified `bridged_network`. + /// + /// Parameters: + /// + /// * `bridged_network`: Network where we want to remove + #[pallet::weight(T::WeightInfo::remove_bridge_config())] + pub fn remove_bridge_config( + origin: OriginFor, + bridged_network: NetworkId, + ) -> DispatchResult { + let _ = ensure_root(origin)?; + ensure!(Bridges::::contains_key(bridged_network), Error::::InvalidConfiguration); + + Bridges::::remove(bridged_network); + Self::deposit_event(Event::BridgeRemoved); + Ok(()) + } + + /// Updates bridge configuration for specified `bridged_network`. + /// + /// Parameters: + /// + /// * `bridged_network`: Network where we want to remove + /// * `fee`: New fee to update + #[pallet::weight(T::WeightInfo::update_bridge_config())] + pub fn update_bridge_config( + origin: OriginFor, + bridged_network: NetworkId, + fee: Option, + ) -> DispatchResult { + let _ = ensure_root(origin)?; + ensure!(Bridges::::contains_key(bridged_network), Error::::InvalidConfiguration); + + Bridges::::try_mutate_exists(bridged_network, |bridge_config| { + let deposit = bridge_config.as_mut().ok_or(Error::::InvalidConfiguration)?; + deposit.fee = fee; + Self::deposit_event(Event::BridgeUpdated); + Ok(()) + }) + } } impl Pallet { @@ -156,10 +245,7 @@ pub mod pallet { .map_err(|_| Error::::UnsupportedDestination)?; ensure!(local_network != remote_network, Error::::UnsupportedDestination); ensure!( - T::SupportedBridges::get() - .iter() - .find(|sb| sb.0 == remote_network) - .is_some(), + Bridges::::contains_key(remote_network), Error::::UnsupportedDestination ); Ok(location) @@ -183,6 +269,16 @@ pub mod pallet { } } } + + impl ExporterFor for Pallet { + fn exporter_for( + network: &NetworkId, + _remote_location: &InteriorMultiLocation, + _message: &Xcm<()>, + ) -> Option<(MultiLocation, Option)> { + Bridges::::get(network).map(Into::into) + } + } } #[cfg(test)] @@ -190,13 +286,15 @@ mod tests { use super::*; use crate as bridge_assets_transfer; - use frame_support::{parameter_types, sp_io, sp_tracing}; + use frame_support::{ + assert_noop, assert_ok, dispatch::DispatchError, parameter_types, sp_io, sp_tracing, + }; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, IdentityLookup}, }; use sp_version::RuntimeVersion; - use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; + use xcm_builder::{ExporterFor, UnpaidRemoteExporter}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -297,17 +395,14 @@ mod tests { } /// Bridge router, which wraps and sends xcm to BridgeHub to be delivered to the different GlobalConsensus - pub type TestBridgeXcmSender = UnpaidRemoteExporter< - NetworkExportTable, - ThreadLocalXcmRouter, - UniversalLocation, - >; + pub type TestBridgeXcmSender = + UnpaidRemoteExporter; impl Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgeXcmSender = TestBridgeXcmSender; - type SupportedBridges = TestBridgeTable; type UniversalLocation = UniversalLocation; + type WeightInfo = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { @@ -321,6 +416,13 @@ mod tests { #[test] fn test_ensure_remote_destination() { new_test_ext().execute_with(|| { + // insert bridge config + assert_ok!(BridgeAssetsTransfer::add_bridge_config( + RuntimeOrigin::root(), + Wococo, + BridgeConfig { bridge_location: (Parent, Parachain(1013)).into(), fee: None }, + )); + // v2 not supported assert_eq!( BridgeAssetsTransfer::ensure_remote_destination(VersionedMultiLocation::V2( @@ -365,6 +467,13 @@ mod tests { #[test] fn test_transfer_asset_via_bridge_works() { new_test_ext().execute_with(|| { + // insert bridge config + assert_ok!(BridgeAssetsTransfer::add_bridge_config( + RuntimeOrigin::root(), + Wococo, + BridgeConfig { bridge_location: (Parent, Parachain(1013)).into(), fee: None }, + )); + assert!(ROUTED_MESSAGE.with(|r| r.borrow().is_none())); let assets = VersionedMultiAssets::V3(MultiAssets::default()); @@ -382,4 +491,94 @@ mod tests { assert!(ROUTED_MESSAGE.with(|r| r.borrow().is_some())); }); } + + #[test] + fn test_bridge_config_management_works() { + let bridged_network = Rococo; + let bridged_config = + BridgeConfig { bridge_location: (Parent, Parachain(1013)).into(), fee: None }; + let dummy_xcm = Xcm(vec![]); + let dummy_remote_interior_multilocation = X1(Parachain(1234)); + + new_test_ext().execute_with(|| { + assert_eq!(Bridges::::iter().count(), 0); + + // should fail - just root is allowed + assert_noop!( + BridgeAssetsTransfer::add_bridge_config( + RuntimeOrigin::signed(1), + bridged_network, + bridged_config.clone(), + ), + DispatchError::BadOrigin + ); + assert_eq!(Bridges::::iter().count(), 0); + assert_eq!( + BridgeAssetsTransfer::exporter_for( + &bridged_network, + &dummy_remote_interior_multilocation, + &dummy_xcm + ), + None + ); + + // add with root + assert_ok!(BridgeAssetsTransfer::add_bridge_config( + RuntimeOrigin::root(), + bridged_network, + bridged_config.clone(), + )); + assert_eq!(Bridges::::iter().count(), 1); + assert_eq!(Bridges::::get(bridged_network), Some(bridged_config.clone())); + assert_eq!(Bridges::::get(Wococo), None); + assert_eq!( + BridgeAssetsTransfer::exporter_for( + &bridged_network, + &dummy_remote_interior_multilocation, + &dummy_xcm + ), + Some(bridged_config.clone().into()) + ); + assert_eq!( + BridgeAssetsTransfer::exporter_for( + &Wococo, + &dummy_remote_interior_multilocation, + &dummy_xcm + ), + None + ); + + // update fee + // remove + assert_ok!(BridgeAssetsTransfer::update_bridge_config( + RuntimeOrigin::root(), + bridged_network, + Some((Parent, 200u128).into()), + )); + assert_eq!(Bridges::::iter().count(), 1); + assert_eq!( + Bridges::::get(bridged_network), + Some(BridgeConfig { + bridge_location: bridged_config.bridge_location.clone(), + fee: Some((Parent, 200u128).into()) + }) + ); + assert_eq!( + BridgeAssetsTransfer::exporter_for( + &bridged_network, + &dummy_remote_interior_multilocation, + &dummy_xcm + ), + Some((bridged_config.bridge_location, Some((Parent, 200u128).into()))) + ); + + // remove + assert_ok!(BridgeAssetsTransfer::remove_bridge_config( + RuntimeOrigin::root(), + bridged_network, + )); + assert_eq!(Bridges::::get(bridged_network), None); + assert_eq!(Bridges::::iter().count(), 0); + }) + } } diff --git a/parachains/pallets/bridge-assets-transfer/src/weights.rs b/parachains/pallets/bridge-assets-transfer/src/weights.rs new file mode 100644 index 0000000000..43ea26858a --- /dev/null +++ b/parachains/pallets/bridge-assets-transfer/src/weights.rs @@ -0,0 +1,91 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// 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 + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_alliance. +pub trait WeightInfo { + fn transfer_asset_via_bridge(/* number of assets */) -> Weight; + fn add_bridge_config() -> Weight; + fn remove_bridge_config() -> Weight; + 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 +impl WeightInfo for () { + 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() + } +} diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 2e3109b1d5..4c074b5675 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -68,7 +68,7 @@ cumulus-primitives-utility = { path = "../../../../primitives/utility", default- pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } -bridge-assets-transfer = { path = "../../../../parachains/pallets/bridge-assets-transfer", default-features = false } +pallet-bridge-assets-transfer = { path = "../../../../parachains/pallets/bridge-assets-transfer", default-features = false } pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true } @@ -101,6 +101,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-bridge-assets-transfer/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -126,6 +127,7 @@ try-runtime = [ "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", + "pallet-bridge-assets-transfer/try-runtime", ] std = [ "codec/std", @@ -178,5 +180,5 @@ std = [ "pallet-collator-selection/std", "parachain-info/std", "parachains-common/std", - "bridge-assets-transfer/std", + "pallet-bridge-assets-transfer/std", ] diff --git a/parachains/runtimes/assets/statemine/src/lib.rs b/parachains/runtimes/assets/statemine/src/lib.rs index e64ed09565..4fbc4de021 100644 --- a/parachains/runtimes/assets/statemine/src/lib.rs +++ b/parachains/runtimes/assets/statemine/src/lib.rs @@ -74,7 +74,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::latest::BodyId; use xcm_executor::XcmExecutor; -use crate::xcm_config::{BridgeTable, UniversalLocation}; +use crate::xcm_config::UniversalLocation; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; impl_opaque_keys! { @@ -570,11 +570,11 @@ impl pallet_uniques::Config for Runtime { type Locker = (); } -impl bridge_assets_transfer::Config for Runtime { +impl pallet_bridge_assets_transfer::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgeXcmSender = BridgeXcmSender; - type SupportedBridges = BridgeTable; type UniversalLocation = UniversalLocation; + type WeightInfo = pallet_bridge_assets_transfer::weights::SubstrateWeight; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -619,7 +619,7 @@ construct_runtime!( // The main stage. TrustBackedAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, - BridgeAssetsTransfer: bridge_assets_transfer::{Pallet, Call, Event} = 52, + BridgeAssetsTransfer: pallet_bridge_assets_transfer::{Pallet, Call, Event} = 52, } ); diff --git a/parachains/runtimes/assets/statemine/src/xcm_config.rs b/parachains/runtimes/assets/statemine/src/xcm_config.rs index d5c9e41e9e..fe69359750 100644 --- a/parachains/runtimes/assets/statemine/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemine/src/xcm_config.rs @@ -14,8 +14,8 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, AssetId, Authorship, Balance, Balances, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + AccountId, AllPalletsWithSystem, AssetId, Authorship, Balance, Balances, BridgeAssetsTransfer, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TrustBackedAssets, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; use frame_support::{ @@ -36,10 +36,10 @@ use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, CurrencyAdapter, EnsureXcmOrigin, FungiblesAdapter, IsConcrete, - NativeAsset, NetworkExportTable, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UnpaidRemoteExporter, - UsingComponents, WeightInfoBounds, + NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, UnpaidRemoteExporter, UsingComponents, + WeightInfoBounds, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -268,14 +268,5 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -parameter_types! { - /// BridgedNetworkConsensus + Multilocation-to-LocalGlobalConsensusBridgeHub + LocalGlobalConsensusBridgeHub - pub BridgeTable: sp_std::prelude::Vec<(NetworkId, MultiLocation, Option)> = sp_std::vec![ - (NetworkId::Wococo, (Parent, Parachain(1013)).into(), None), - (NetworkId::Polkadot, (Parent, Parachain(1003)).into(), None), - ]; -} - /// Bridge router, which wraps and sends xcm to BridgeHub to be delivered to the different GlobalConsensus -pub type BridgeXcmSender = - UnpaidRemoteExporter, XcmRouter, UniversalLocation>; +pub type BridgeXcmSender = UnpaidRemoteExporter;