diff --git a/pallets/runtime/common/src/runtime.rs b/pallets/runtime/common/src/runtime.rs index 7808e6fbc..85c2c9f1b 100644 --- a/pallets/runtime/common/src/runtime.rs +++ b/pallets/runtime/common/src/runtime.rs @@ -482,6 +482,7 @@ macro_rules! misc_pallet_impls { type MaxNumberOfNFTsPerLeg = MaxNumberOfNFTsPerLeg; type MaxNumberOfNFTs = MaxNumberOfNFTs; type MaxNumberOfOffChainAssets = MaxNumberOfOffChainAssets; + type MaxNumberOfPortfolios = MaxNumberOfPortfolios; type MaxNumberOfVenueSigners = MaxNumberOfVenueSigners; type MaxInstructionMediators = MaxInstructionMediators; } diff --git a/pallets/runtime/develop/src/runtime.rs b/pallets/runtime/develop/src/runtime.rs index c3e9c73c7..4dd10e269 100644 --- a/pallets/runtime/develop/src/runtime.rs +++ b/pallets/runtime/develop/src/runtime.rs @@ -93,6 +93,7 @@ parameter_types! { pub const MaxNumberOfFungibleAssets: u32 = 10; pub const MaxNumberOfNFTsPerLeg: u32 = 10; pub const MaxNumberOfNFTs: u32 = 100; + pub const MaxNumberOfPortfolios: u32 = (10 + 100) * 2; pub const MaxNumberOfVenueSigners: u32 = 50; pub const MaxInstructionMediators: u32 = 4; diff --git a/pallets/runtime/mainnet/src/runtime.rs b/pallets/runtime/mainnet/src/runtime.rs index c76350970..7eec8d5d2 100644 --- a/pallets/runtime/mainnet/src/runtime.rs +++ b/pallets/runtime/mainnet/src/runtime.rs @@ -89,6 +89,7 @@ parameter_types! { pub const MaxNumberOfFungibleAssets: u32 = 10; pub const MaxNumberOfNFTsPerLeg: u32 = 10; pub const MaxNumberOfNFTs: u32 = 100; + pub const MaxNumberOfPortfolios: u32 = (10 + 100) * 2; pub const MaxNumberOfVenueSigners: u32 = 50; pub const MaxInstructionMediators: u32 = 4; diff --git a/pallets/runtime/testnet/src/runtime.rs b/pallets/runtime/testnet/src/runtime.rs index 70aeafe02..d67fe26a0 100644 --- a/pallets/runtime/testnet/src/runtime.rs +++ b/pallets/runtime/testnet/src/runtime.rs @@ -92,6 +92,7 @@ parameter_types! { pub const MaxNumberOfFungibleAssets: u32 = 10; pub const MaxNumberOfNFTsPerLeg: u32 = 10; pub const MaxNumberOfNFTs: u32 = 100; + pub const MaxNumberOfPortfolios: u32 = (10 + 100) * 2; pub const MaxNumberOfVenueSigners: u32 = 50; pub const MaxInstructionMediators: u32 = 4; diff --git a/pallets/runtime/tests/src/asset_pallet/base_transfer.rs b/pallets/runtime/tests/src/asset_pallet/base_transfer.rs index d5386fe13..274172c89 100644 --- a/pallets/runtime/tests/src/asset_pallet/base_transfer.rs +++ b/pallets/runtime/tests/src/asset_pallet/base_transfer.rs @@ -11,7 +11,7 @@ use polymesh_primitives::{ }; use super::setup::{create_and_issue_sample_asset, create_and_issue_sample_nft, ISSUE_AMOUNT}; -use crate::storage::User; +use crate::storage::{default_portfolio_btreeset, User}; use crate::{ExtBuilder, TestStorage}; type Asset = pallet_asset::Module; @@ -229,7 +229,7 @@ fn base_transfer_locked_asset() { asset_id, amount: ISSUE_AMOUNT, }], - vec![alice_default_portfolio], + default_portfolio_btreeset(alice.did), None, )); let mut weight_meter = WeightMeter::max_limit_no_minimum(); diff --git a/pallets/runtime/tests/src/asset_pallet/controller_transfer.rs b/pallets/runtime/tests/src/asset_pallet/controller_transfer.rs index a7dd0ecc3..ec5642569 100644 --- a/pallets/runtime/tests/src/asset_pallet/controller_transfer.rs +++ b/pallets/runtime/tests/src/asset_pallet/controller_transfer.rs @@ -8,7 +8,7 @@ use polymesh_primitives::settlement::{ use polymesh_primitives::{AuthorizationData, PortfolioId, PortfolioKind, Signatory}; use super::setup::{create_and_issue_sample_asset, ISSUE_AMOUNT}; -use crate::storage::User; +use crate::storage::{default_portfolio_btreeset, User}; use crate::{ExtBuilder, TestStorage}; type Asset = pallet_asset::Module; @@ -71,7 +71,7 @@ fn controller_transfer_locked_asset() { assert_ok!(Settlement::affirm_instruction( alice.origin(), InstructionId(0), - vec![alice_default_portfolio] + default_portfolio_btreeset(alice.did), ),); // Controller transfer should fail since the tokens are locked diff --git a/pallets/runtime/tests/src/asset_test.rs b/pallets/runtime/tests/src/asset_test.rs index 726050efb..ac6f9fe97 100644 --- a/pallets/runtime/tests/src/asset_test.rs +++ b/pallets/runtime/tests/src/asset_test.rs @@ -56,8 +56,8 @@ use crate::asset_pallet::setup::{ use crate::ext_builder::ExtBuilder; use crate::nft::create_nft_collection; use crate::storage::{ - add_secondary_key, add_secondary_key_with_perms, register_keyring_account, root, Checkpoint, - TestStorage, User, + add_secondary_key, add_secondary_key_with_perms, default_portfolio_btreeset, + register_keyring_account, root, Checkpoint, TestStorage, User, }; type BaseError = pallet_base::Error; @@ -1954,7 +1954,7 @@ fn controller_transfer_locked_asset() { assert_ok!(Settlement::affirm_instruction( alice.origin(), InstructionId(0), - vec![alice_default_portfolio] + default_portfolio_btreeset(alice.did), ),); // Controller transfer should fail since the tokens are locked diff --git a/pallets/runtime/tests/src/nft.rs b/pallets/runtime/tests/src/nft.rs index ca6531dae..be96ee3c9 100644 --- a/pallets/runtime/tests/src/nft.rs +++ b/pallets/runtime/tests/src/nft.rs @@ -26,7 +26,7 @@ use sp_keyring::AccountKeyring; use super::asset_test::{get_asset_details, set_timestamp}; use crate::asset_pallet::setup::{create_and_issue_sample_asset, create_and_issue_sample_nft}; use crate::ext_builder::ExtBuilder; -use crate::storage::{TestStorage, User}; +use crate::storage::{default_portfolio_btreeset, TestStorage, User}; type Asset = pallet_asset::Module; type ComplianceManager = pallet_compliance_manager::Module; @@ -1179,7 +1179,7 @@ fn redeem_locked_nft() { None, None, legs, - vec![PortfolioId::default_portfolio(alice.did)], + default_portfolio_btreeset(alice.did), None, )); @@ -1221,7 +1221,7 @@ fn reject_instruction_with_locked_asset() { None, None, legs, - vec![PortfolioId::default_portfolio(alice.did)], + default_portfolio_btreeset(alice.did), None, )); diff --git a/pallets/runtime/tests/src/portfolio.rs b/pallets/runtime/tests/src/portfolio.rs index db3661765..d8d1d56d8 100644 --- a/pallets/runtime/tests/src/portfolio.rs +++ b/pallets/runtime/tests/src/portfolio.rs @@ -22,7 +22,7 @@ use sp_keyring::AccountKeyring; use super::asset_pallet::setup::{create_and_issue_sample_asset, ISSUE_AMOUNT}; use super::asset_test::max_len_bytes; use super::nft::{create_nft_collection, mint_nft}; -use super::storage::{EventTest, System, TestStorage, User}; +use super::storage::{user_portfolio_btreeset, EventTest, System, TestStorage, User}; use super::ExtBuilder; type Asset = pallet_asset::Module; @@ -683,7 +683,7 @@ fn delete_portfolio_with_locked_nfts() { None, None, legs, - vec![PortfolioId::user_portfolio(alice.did, PortfolioNumber(1))], + user_portfolio_btreeset(alice.did, PortfolioNumber(1)), Some(Memo::default()), )); diff --git a/pallets/runtime/tests/src/settlement_pallet/execute_instruction.rs b/pallets/runtime/tests/src/settlement_pallet/execute_instruction.rs index 145c4b062..58cf3bf5c 100644 --- a/pallets/runtime/tests/src/settlement_pallet/execute_instruction.rs +++ b/pallets/runtime/tests/src/settlement_pallet/execute_instruction.rs @@ -16,7 +16,7 @@ use polymesh_primitives::PortfolioId; use super::setup::create_and_issue_sample_asset_with_venue; use crate::asset_pallet::setup::create_and_issue_sample_asset; -use crate::storage::User; +use crate::storage::{default_portfolio_btreeset, User}; use crate::{next_block, ExtBuilder, TestStorage}; type Settlement = pallet_settlement::Module; @@ -50,12 +50,12 @@ fn execute_instruction_storage_pruning() { assert_ok!(Settlement::affirm_instruction( alice.origin(), instruction_id, - vec![alice_default_portfolio] + default_portfolio_btreeset(alice.did), )); assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - vec![bob_default_portfolio] + default_portfolio_btreeset(bob.did), )); next_block(); @@ -144,12 +144,12 @@ fn execute_instruction_storage_rollback() { assert_ok!(Settlement::affirm_instruction( alice.origin(), instruction_id, - vec![alice_default_portfolio] + default_portfolio_btreeset(alice.did), )); assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - vec![bob_default_portfolio] + default_portfolio_btreeset(bob.did), )); // Removes asset_id2 balance to force an error BalanceOf::insert(asset_id2, alice.did, 0); diff --git a/pallets/runtime/tests/src/settlement_test.rs b/pallets/runtime/tests/src/settlement_test.rs index f7cc44ce5..954750745 100644 --- a/pallets/runtime/tests/src/settlement_test.rs +++ b/pallets/runtime/tests/src/settlement_test.rs @@ -5,8 +5,8 @@ use std::ops::Deref; use codec::Encode; use frame_support::dispatch::DispatchErrorWithPostInfo; use frame_support::{ - assert_err_ignore_postinfo, assert_noop, assert_ok, assert_storage_noop, - IterableStorageDoubleMap, StorageDoubleMap, StorageMap, + assert_err_ignore_postinfo, assert_noop, assert_ok, assert_storage_noop, traits::TryCollect, + BoundedBTreeSet, IterableStorageDoubleMap, StorageDoubleMap, StorageMap, }; use rand::{prelude::*, thread_rng}; use sp_runtime::{AccountId32, AnySignature}; @@ -45,7 +45,8 @@ use super::asset_test::max_len_bytes; use super::nft::{create_nft_collection, mint_nft}; use super::settlement_pallet::setup::create_and_issue_sample_asset_with_venue; use super::storage::{ - default_portfolio_vec, make_account_with_balance, user_portfolio_vec, TestStorage, User, + default_portfolio_btreeset, make_account_with_balance, user_portfolio_btreeset, + vec_to_btreeset, TestStorage, User, }; use super::{next_block, ExtBuilder}; @@ -78,7 +79,7 @@ macro_rules! assert_affirm_instruction { assert_ok!(Settlement::affirm_instruction( $signer, $instruction_id, - default_portfolio_vec($did), + default_portfolio_btreeset($did), )); }; } @@ -356,11 +357,11 @@ fn create_and_affirm_instruction() { // If affirmation fails, the instruction should be rolled back. // i.e. this tx should be a no-op. assert_noop!( - add_and_affirm_tx(user_portfolio_vec(alice.did, 1u64.into())), + add_and_affirm_tx(user_portfolio_btreeset(alice.did, 1u64.into())), Error::UnexpectedAffirmationStatus ); - assert_ok!(add_and_affirm_tx(default_portfolio_vec(alice.did))); + assert_ok!(add_and_affirm_tx(default_portfolio_btreeset(alice.did))); alice.assert_all_balances_unchanged(); bob.assert_all_balances_unchanged(); @@ -412,7 +413,7 @@ fn overdraft_failure() { Settlement::affirm_instruction( alice.origin(), instruction_id, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), ), PortfolioError::InsufficientPortfolioBalance ); @@ -509,7 +510,7 @@ fn token_swap() { assert_ok!(Settlement::withdraw_affirmation( alice.origin(), instruction_id, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), )); assert_affirms_pending(instruction_id, 2); @@ -684,7 +685,7 @@ fn failed_execution() { assert_ok!(ComplianceManager::add_compliance_requirement( bob.origin(), asset_id2, - Vec::new(), + Default::default(), vec![Condition { condition_type: ConditionType::IsPresent(Claim::Jurisdiction( CountryCode::BR, @@ -882,7 +883,7 @@ fn venue_filtering() { None, None, legs.clone(), - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), None, )); @@ -1017,7 +1018,7 @@ fn basic_fuzzing() { assert_ok!(Settlement::withdraw_affirmation( user.origin(), instruction_id, - default_portfolio_vec(user.did), + default_portfolio_btreeset(user.did), )); } } @@ -1060,7 +1061,7 @@ fn basic_fuzzing() { assert_ok!(Settlement::withdraw_affirmation( users[failed_user].origin(), instruction_id, - default_portfolio_vec(users[failed_user].did), + default_portfolio_btreeset(users[failed_user].did), )); locked_assets.retain(|(did, _), _| *did != users[failed_user].did); } @@ -1210,7 +1211,7 @@ fn claim_multiple_receipts_during_authorization() { None ), ], - Vec::new(), + Default::default(), ), Error::DuplicateReceiptUid ); @@ -1236,7 +1237,7 @@ fn claim_multiple_receipts_during_authorization() { None ), ], - Vec::new(), + Default::default(), )); assert_affirms_pending(id, 0); @@ -1492,7 +1493,7 @@ fn cross_portfolio_settlement() { Settlement::affirm_instruction( bob.origin(), instruction_id, - default_portfolio_vec(bob.did), + default_portfolio_btreeset(bob.did), ), Error::UnexpectedAffirmationStatus ); @@ -1502,7 +1503,7 @@ fn cross_portfolio_settlement() { assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - user_portfolio_vec(bob.did, num), + user_portfolio_btreeset(bob.did, num), )); // Instruction should've settled @@ -1581,10 +1582,10 @@ fn multiple_portfolio_settlement() { Settlement::withdraw_affirmation( alice.origin(), instruction_id, - vec![ + vec_to_btreeset(vec![ PortfolioId::default_portfolio(alice.did), PortfolioId::user_portfolio(alice.did, alice_num) - ], + ]), ), Error::UnexpectedAffirmationStatus ); @@ -1594,7 +1595,7 @@ fn multiple_portfolio_settlement() { Settlement::affirm_instruction( alice.origin(), instruction_id, - user_portfolio_vec(alice.did, alice_num), + user_portfolio_btreeset(alice.did, alice_num), ), PortfolioError::InsufficientPortfolioBalance ); @@ -1614,7 +1615,7 @@ fn multiple_portfolio_settlement() { assert_ok!(Settlement::affirm_instruction( alice.origin(), instruction_id, - user_portfolio_vec(alice.did, alice_num), + user_portfolio_btreeset(alice.did, alice_num), )); alice.assert_all_balances_unchanged(); bob.assert_all_balances_unchanged(); @@ -1629,16 +1630,19 @@ fn multiple_portfolio_settlement() { ); // Bob approves the instruction with both of his portfolios in a single transaction - let portfolios_vec = vec![ + let portfolios_set: BoundedBTreeSet<_, _> = [ PortfolioId::default_portfolio(bob.did), PortfolioId::user_portfolio(bob.did, bob_num), - ]; + ] + .into_iter() + .try_collect() + .expect("Two portfolios isn't too many"); next_block(); assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - portfolios_vec, + portfolios_set, )); // Instruction should've settled @@ -1726,15 +1730,18 @@ fn multiple_custodian_settlement() { assert_locked_assets(&asset_id, &alice, 0); // Alice approves the instruction from both of her portfolios - let portfolios_vec = vec![ + let portfolios_set: BoundedBTreeSet<_, _> = [ PortfolioId::default_portfolio(alice.did), PortfolioId::user_portfolio(alice.did, alice_num), - ]; + ] + .into_iter() + .try_collect() + .expect("Two portfolios isn't too many"); set_current_block_number(10); assert_ok!(Settlement::affirm_instruction( alice.origin(), instruction_id, - portfolios_vec.clone(), + portfolios_set.clone(), )); alice.assert_all_balances_unchanged(); bob.assert_all_balances_unchanged(); @@ -1758,10 +1765,13 @@ fn multiple_custodian_settlement() { assert_ok!(Portfolio::accept_portfolio_custody(bob.origin(), auth_id2)); // Bob fails to approve the instruction with both of his portfolios since he doesn't have custody for the second one - let portfolios_bob = vec![ + let portfolios_bob: BoundedBTreeSet<_, _> = [ PortfolioId::default_portfolio(bob.did), PortfolioId::user_portfolio(bob.did, bob_num), - ]; + ] + .into_iter() + .try_collect() + .expect("Two portfolios isn't too many"); assert_noop!( Settlement::affirm_instruction(bob.origin(), instruction_id, portfolios_bob), PortfolioError::UnauthorizedCustodian @@ -1774,7 +1784,7 @@ fn multiple_custodian_settlement() { // Alice fails to deny the instruction from both her portfolios since she doesn't have the custody next_block(); assert_noop!( - Settlement::withdraw_affirmation(alice.origin(), instruction_id, portfolios_vec,), + Settlement::withdraw_affirmation(alice.origin(), instruction_id, portfolios_set,), PortfolioError::UnauthorizedCustodian ); @@ -1782,15 +1792,18 @@ fn multiple_custodian_settlement() { assert_ok!(Settlement::withdraw_affirmation( alice.origin(), instruction_id, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), )); assert_locked_assets(&asset_id, &alice, 0); // Alice can authorize instruction from remaining portfolios since she has the custody - let portfolios_final = vec![ + let portfolios_final: BoundedBTreeSet<_, _> = [ PortfolioId::default_portfolio(alice.did), PortfolioId::user_portfolio(bob.did, bob_num), - ]; + ] + .into_iter() + .try_collect() + .expect("Two portfolios isn't too many"); next_block(); assert_ok!(Settlement::affirm_instruction( alice.origin(), @@ -1951,7 +1964,7 @@ fn reject_failed_instruction() { assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - default_portfolio_vec(bob.did), + default_portfolio_btreeset(bob.did), )); // Resume compliance to cause transfer failure. @@ -1967,7 +1980,7 @@ fn reject_failed_instruction() { assert_ok!(ComplianceManager::add_compliance_requirement( alice.origin(), asset_id, - Vec::new(), + Default::default(), vec![Condition { condition_type: ConditionType::IsPresent(Claim::Jurisdiction( CountryCode::BR, @@ -2302,7 +2315,7 @@ fn create_instruction( asset_id, amount }], - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), None, )); instruction_id @@ -2691,7 +2704,7 @@ fn add_and_affirm_nft_instruction() { None, None, legs, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), Some(Memo::default()), )); @@ -2716,7 +2729,7 @@ fn add_and_affirm_nft_instruction() { assert_ok!(Settlement::affirm_instruction( bob.origin(), instruction_id, - default_portfolio_vec(bob.did), + default_portfolio_btreeset(bob.did), )); next_block(); assert_eq!(NumberOfNFTs::get(asset_id, alice.did), 0); @@ -2800,7 +2813,7 @@ fn add_and_affirm_nft_not_owned() { None, None, legs, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), Some(Memo::default()), ), PortfolioError::NFTNotFoundInPortfolio @@ -2868,7 +2881,7 @@ fn add_same_nft_different_legs() { None, None, legs, - default_portfolio_vec(alice.did), + default_portfolio_btreeset(alice.did), Some(Memo::default()), ), PortfolioError::NFTAlreadyLocked @@ -2942,7 +2955,7 @@ fn add_and_affirm_with_receipts_nfts() { .into(), None )], - Vec::new(), + Default::default(), ), Error::ReceiptForInvalidLegType ); @@ -3045,7 +3058,7 @@ fn add_and_execute_offchain_instruction() { alice.origin(), id, receipts_details, - Vec::new(), + Default::default(), ),); next_block(); @@ -3090,7 +3103,6 @@ fn affirm_offchain_asset_without_receipt() { VenueType::Other, ) .unwrap(); - let alice_portfolio = PortfolioId::default_portfolio(alice.did); let legs: Vec = vec![Leg::OffChain { sender_identity: alice.did, @@ -3111,7 +3123,7 @@ fn affirm_offchain_asset_without_receipt() { Settlement::affirm_instruction( alice.origin(), InstructionId(0), - vec![alice_portfolio], + default_portfolio_btreeset(alice.did), ), Error::UnexpectedAffirmationStatus ); @@ -3471,13 +3483,13 @@ fn manually_execute_failed_instruction() { None, None, legs.clone(), - vec![alice_default_portfolio], + default_portfolio_btreeset(alice.did), instruction_memo.clone(), )); assert_ok!(Settlement::affirm_instruction( bob.origin(), InstructionId(0), - vec![bob_default_portfolio], + default_portfolio_btreeset(bob.did), )); assert_ok!(Asset::freeze(alice.origin(), asset_id)); next_block(); @@ -3549,7 +3561,7 @@ fn affirm_with_receipts_cost() { alice.origin(), id, receipts_details, - Vec::new(), + Default::default(), Some(affirmation_count) ), Error::NumberOfOffChainTransfersUnderestimated @@ -3602,7 +3614,7 @@ fn affirm_instruction_cost() { Settlement::affirm_instruction_with_count( alice.origin(), InstructionId(0), - vec![alice_user_porfolio, alice_default_portfolio], + vec_to_btreeset(vec![alice_user_porfolio, alice_default_portfolio]), Some(affirmation_count) ), Error::NumberOfFungibleTransfersUnderestimated @@ -3613,7 +3625,7 @@ fn affirm_instruction_cost() { Settlement::affirm_instruction_with_count( bob.origin(), InstructionId(0), - vec![bob_user_porfolio, bob_default_portfolio], + vec_to_btreeset(vec![bob_user_porfolio, bob_default_portfolio]), Some(affirmation_count) ), Error::NumberOfFungibleTransfersUnderestimated @@ -3653,7 +3665,7 @@ fn withdraw_affirmation_cost() { assert_ok!(Settlement::affirm_instruction_with_count( alice.origin(), InstructionId(0), - vec![alice_default_portfolio], + default_portfolio_btreeset(alice.did), Some(affirmation_count) ),); let affirmation_count = @@ -3662,7 +3674,7 @@ fn withdraw_affirmation_cost() { Settlement::withdraw_affirmation_with_count( alice.origin(), InstructionId(0), - vec![alice_default_portfolio], + default_portfolio_btreeset(alice.did), Some(affirmation_count) ), Error::NumberOfFungibleTransfersUnderestimated @@ -3686,7 +3698,12 @@ fn reject_instruction_cost() { AssetType::NonFungible(NonFungibleType::Derivative), NFTCollectionKeys::default(), ); - mint_nft(alice.clone(), asset_id2, Vec::new(), PortfolioKind::Default); + mint_nft( + alice.clone(), + asset_id2, + Default::default(), + PortfolioKind::Default, + ); let legs: Vec = vec![ Leg::Fungible { @@ -4018,12 +4035,12 @@ fn expired_affirmation_execution() { assert_ok!(Settlement::affirm_instruction( alice.origin(), InstructionId(0), - vec![alice_default_portfolio] + default_portfolio_btreeset(alice.did), ),); assert_ok!(Settlement::affirm_instruction( bob.origin(), InstructionId(0), - vec![bob_default_portfolio] + default_portfolio_btreeset(bob.did), ),); assert_ok!(Settlement::affirm_instruction_as_mediator( charlie.origin(), diff --git a/pallets/runtime/tests/src/storage.rs b/pallets/runtime/tests/src/storage.rs index 8e1924662..27cca73de 100644 --- a/pallets/runtime/tests/src/storage.rs +++ b/pallets/runtime/tests/src/storage.rs @@ -6,14 +6,17 @@ use std::convert::From; use codec::Encode; use frame_support::dispatch::{DispatchInfo, DispatchResult, Weight}; -use frame_support::traits::{Currency, Imbalance, KeyOwnerProofSystem, OnInitialize, OnUnbalanced}; +use frame_support::traits::{ + Currency, Imbalance, KeyOwnerProofSystem, OnInitialize, OnUnbalanced, TryCollect, +}; use frame_support::weights::{ RuntimeDbWeight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; -use frame_support::{assert_ok, parameter_types, StorageDoubleMap}; +use frame_support::{assert_ok, parameter_types, BoundedBTreeSet, StorageDoubleMap}; use smallvec::smallvec; use sp_core::crypto::{key_types, Pair as PairTrait}; use sp_core::sr25519::Pair; +use sp_core::Get; use sp_core::H256; use sp_keyring::AccountKeyring; use sp_runtime::curve::PiecewiseLinear; @@ -28,8 +31,6 @@ use sp_runtime::transaction_validity::{ }; use sp_runtime::{create_runtime_str, AnySignature, KeyTypeId, Perbill, Permill}; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::collections::btree_set::BTreeSet; -use sp_std::iter; use sp_version::RuntimeVersion; use frame_system::{EnsureRoot, RawOrigin}; @@ -235,6 +236,7 @@ parameter_types! { pub const MaxNumberOfFungibleMoves: u32 = 10; pub const MaxNumberOfNFTsMoves: u32 = 100; pub const MaxNumberOfOffChainAssets: u32 = 10; + pub const MaxNumberOfPortfolios: u32 = (10 + 100) * 2; pub const MaxNumberOfVenueSigners: u32 = 50; pub const MaxInstructionMediators: u32 = 4; pub const MaxAssetMediators: u32 = 4; @@ -892,8 +894,20 @@ pub fn get_last_auth_id(signatory: &Signatory) -> u64 { } /// Returns a btreeset that contains default portfolio for the identity. -pub fn default_portfolio_btreeset(did: IdentityId) -> BTreeSet { - iter::once(PortfolioId::default_portfolio(did)).collect::>() +pub fn default_portfolio_btreeset( + did: IdentityId, +) -> BoundedBTreeSet { + [PortfolioId::default_portfolio(did)] + .into_iter() + .try_collect() + .expect("One portfolio shouldn't be too much") +} + +/// Returns a Bounded btreeset from an unbounded Vec. +pub fn vec_to_btreeset>(vec: Vec) -> BoundedBTreeSet { + vec.into_iter() + .try_collect() + .expect("Vec has too many items") } /// Returns a vector that contains default portfolio for the identity. @@ -902,8 +916,14 @@ pub fn default_portfolio_vec(did: IdentityId) -> Vec { } /// Returns a btreeset that contains a portfolio for the identity. -pub fn user_portfolio_btreeset(did: IdentityId, num: PortfolioNumber) -> BTreeSet { - iter::once(PortfolioId::user_portfolio(did, num)).collect::>() +pub fn user_portfolio_btreeset( + did: IdentityId, + num: PortfolioNumber, +) -> BoundedBTreeSet { + [PortfolioId::user_portfolio(did, num)] + .into_iter() + .try_collect() + .expect("One portfolio shouldn't be too much") } /// Returns a vector that contains a portfolio for the identity. diff --git a/pallets/settlement/src/benchmarking.rs b/pallets/settlement/src/benchmarking.rs index d97dcfeb7..7c944db4e 100644 --- a/pallets/settlement/src/benchmarking.rs +++ b/pallets/settlement/src/benchmarking.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . pub use frame_benchmarking::{account, benchmarks}; -use frame_support::traits::Get; +use frame_support::traits::{Get, TryCollect}; use frame_system::RawOrigin; use scale_info::prelude::format; use sp_core::sr25519::Signature; @@ -60,12 +60,30 @@ pub struct Parameters { pub asset_mediators: Vec>, } +impl Parameters { + pub fn sdr_portfolios(&self) -> BoundedBTreeSet { + self.portfolios + .sdr_portfolios + .clone() + .into_iter() + .try_collect() + .expect("shouldn't be too many") + } + + pub fn rcv_portfolios(&self) -> BoundedBTreeSet { + self.portfolios + .rcv_portfolios + .clone() + .into_iter() + .try_collect() + .expect("shouldn't be too many") + } +} + #[derive(Default)] pub struct Portfolios { pub sdr_portfolios: Vec, - pub sdr_receipt_portfolios: Vec, pub rcv_portfolios: Vec, - pub rcv_receipt_portfolios: Vec, } fn creator>>() -> User { @@ -231,11 +249,7 @@ where ) }) .collect(); - let sdr_portfolios = [ - parameters.portfolios.sdr_portfolios.clone(), - parameters.portfolios.sdr_receipt_portfolios.clone(), - ] - .concat(); + let sdr_portfolios = parameters.sdr_portfolios(); Module::::affirm_with_receipts( sender.origin.clone().into(), InstructionId(1), @@ -243,11 +257,7 @@ where sdr_portfolios, ) .unwrap(); - let rcv_portfolios = [ - parameters.portfolios.rcv_portfolios.clone(), - parameters.portfolios.rcv_receipt_portfolios.clone(), - ] - .concat(); + let rcv_portfolios = parameters.rcv_portfolios(); Module::::affirm_with_receipts( receiver.origin.clone().into(), InstructionId(1), @@ -434,6 +444,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account()]); let parameters = setup_legs::(&alice, &bob, f, n, o, false, false); + let portfolios = parameters.sdr_portfolios(); Module::::add_instruction( alice.origin.clone().into(), Some(venue_id), @@ -456,8 +467,6 @@ benchmarks! { ) }) .collect(); - let portfolios = - [parameters.portfolios.sdr_portfolios, parameters.portfolios.sdr_receipt_portfolios].concat(); }: _(alice.origin, InstructionId(1), receipt_details, portfolios) execute_manual_instruction { @@ -504,7 +513,8 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account()]); let parameters = setup_legs::(&alice, &bob, f, n, o, false, false); - }: _(alice.origin, Some(venue_id), settlement_type, None, None, parameters.legs, parameters.portfolios.sdr_portfolios, memo) + let portfolios = parameters.sdr_portfolios(); + }: _(alice.origin, Some(venue_id), settlement_type, None, None, parameters.legs, portfolios, memo) affirm_instruction { // Number of fungible and non-fungible assets in the portfolios @@ -517,6 +527,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account()]); let parameters = setup_legs::(&alice, &bob, f, n, T::MaxNumberOfOffChainAssets::get(), false, false); + let portfolios = parameters.sdr_portfolios(); Module::::add_instruction( alice.origin.clone().into(), Some(venue_id), @@ -526,7 +537,7 @@ benchmarks! { parameters.legs, memo, ).unwrap(); - }: _(alice.origin, InstructionId(1), parameters.portfolios.sdr_portfolios) + }: _(alice.origin, InstructionId(1), portfolios) withdraw_affirmation { // Number of fungible, non-fungible and offchain LEGS in the portfolios @@ -542,8 +553,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account(), bob.account()]); let parameters = setup_execute_instruction::(&alice, &bob, settlement_type, venue_id, f, n, o, m, false, false); - let portfolios = - [parameters.portfolios.sdr_portfolios, parameters.portfolios.sdr_receipt_portfolios].concat(); + let portfolios = parameters.sdr_portfolios(); }: _(alice.origin, InstructionId(1), portfolios) reject_instruction { @@ -560,8 +570,6 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account(), bob.account()]); let parameters = setup_execute_instruction::(&alice, &bob, settlement_type, venue_id, f, n, o, m, false, false); - let portfolios = - [parameters.portfolios.sdr_portfolios.clone(), parameters.portfolios.sdr_receipt_portfolios].concat(); }: _(alice.origin, InstructionId(1), parameters.portfolios.sdr_portfolios[0]) execute_instruction_paused { @@ -611,6 +619,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account()]); let parameters = setup_legs::(&alice, &bob, f, n, o, false, false); + let portfolios = parameters.rcv_portfolios(); Module::::add_instruction( alice.origin.clone().into(), Some(venue_id), @@ -633,8 +642,6 @@ benchmarks! { ) }) .collect(); - let portfolios = - [parameters.portfolios.rcv_portfolios, parameters.portfolios.rcv_receipt_portfolios].concat(); }: affirm_with_receipts(bob.origin, InstructionId(1), receipt_details, portfolios) affirm_instruction_rcv { @@ -648,6 +655,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account()]); let parameters = setup_legs::(&alice, &bob, f, n, T::MaxNumberOfOffChainAssets::get(), false, false); + let portfolios = parameters.rcv_portfolios(); Module::::add_instruction( alice.origin.clone().into(), Some(venue_id), @@ -657,7 +665,7 @@ benchmarks! { parameters.legs, memo, ).unwrap(); - }: affirm_instruction(bob.origin, InstructionId(1), parameters.portfolios.rcv_portfolios) + }: affirm_instruction(bob.origin, InstructionId(1), portfolios) withdraw_affirmation_rcv { // Number of fungible, non-fungible and offchain LEGS in the portfolios @@ -673,8 +681,7 @@ benchmarks! { let venue_id = create_venue_::(alice.did(), vec![alice.account(), bob.account()]); let parameters = setup_execute_instruction::(&alice, &bob, settlement_type, venue_id, f, n, o, m, false, false); - let portfolios = - [parameters.portfolios.rcv_portfolios, parameters.portfolios.rcv_receipt_portfolios].concat(); + let portfolios = parameters.rcv_portfolios(); }: withdraw_affirmation(bob.origin, InstructionId(1), portfolios) add_instruction_with_mediators { @@ -709,7 +716,8 @@ benchmarks! { let mediators: BTreeSet = (0..m).map(|i| IdentityId::from(i as u128)).collect(); let parameters = setup_legs::(&alice, &bob, f, n, o, false, false); - }: _(alice.origin, Some(venue_id), settlement_type, None, None, parameters.legs, parameters.portfolios.sdr_portfolios, memo, mediators.try_into().unwrap()) + let portfolios = parameters.sdr_portfolios(); + }: _(alice.origin, Some(venue_id), settlement_type, None, None, parameters.legs, portfolios, memo, mediators.try_into().unwrap()) affirm_instruction_as_mediator { let bob = UserBuilder::::default().generate_did().build("Bob"); diff --git a/pallets/settlement/src/lib.rs b/pallets/settlement/src/lib.rs index ded062b57..75678e127 100644 --- a/pallets/settlement/src/lib.rs +++ b/pallets/settlement/src/lib.rs @@ -135,6 +135,9 @@ pub trait Config: /// Maximum number of off-chain assets that can be transferred in a instruction. type MaxNumberOfOffChainAssets: Get; + /// Maximum number of portfolios. + type MaxNumberOfPortfolios: Get; + /// Maximum number of venue signers. type MaxNumberOfVenueSigners: Get; @@ -257,11 +260,10 @@ decl_storage! { /// Signers allowed by the venue. (venue_id, signer) -> bool VenueSigners get(fn venue_signers): double_map hasher(twox_64_concat) VenueId, hasher(twox_64_concat) T::AccountId => bool; - /// Array of venues created by an identity. Only needed for the UI. IdentityId -> Vec /// Venues create by an identity. /// Only needed for the UI. /// - /// identity -> venue_id () + /// identity -> venue_id -> () pub UserVenues get(fn user_venues): double_map hasher(twox_64_concat) IdentityId, hasher(twox_64_concat) VenueId => (); /// Details about an instruction. instruction_id -> instruction_details @@ -319,6 +321,7 @@ decl_module! { const MaxNumberOfFungibleAssets: u32 = T::MaxNumberOfFungibleAssets::get(); const MaxNumberOfNFTsPerLeg: u32 = T::MaxNumberOfNFTsPerLeg::get(); const MaxNumberOfNFTs: u32 = T::MaxNumberOfNFTs::get(); + const MaxNumberOfPortfolios: u32 = T::MaxNumberOfPortfolios::get(); const MaxNumberOfVenueSigners: u32 = T::MaxNumberOfVenueSigners::get(); fn deposit_event() = default; @@ -408,13 +411,13 @@ decl_module! { origin, id: InstructionId, receipt_details: Vec>, - portfolios: Vec, + portfolios: BoundedBTreeSet, ) -> DispatchResultWithPostInfo { Self::affirm_with_receipts_and_maybe_schedule_instruction( origin, id, receipt_details, - portfolios, + portfolios.into_inner(), None ) } @@ -573,11 +576,10 @@ decl_module! { trade_date: Option, value_date: Option, legs: Vec, - portfolios: Vec, + portfolios: BoundedBTreeSet, instruction_memo: Option, ) { let did = Identity::::ensure_perms(origin.clone())?; - let portfolios_set = portfolios.into_iter().collect::>(); let instruction_id = Self::base_add_instruction( did, venue_id, @@ -591,7 +593,7 @@ decl_module! { Self::affirm_and_maybe_schedule_instruction( origin, instruction_id, - portfolios_set.into_iter(), + portfolios.into_inner(), None ) .map_err(|e| e.error)?; @@ -606,11 +608,11 @@ decl_module! { /// # Permissions /// * Portfolio #[weight = ::WeightInfo::affirm_instruction_input(None, portfolios.len() as u32)] - pub fn affirm_instruction(origin, id: InstructionId, portfolios: Vec) -> DispatchResultWithPostInfo { + pub fn affirm_instruction(origin, id: InstructionId, portfolios: BoundedBTreeSet) -> DispatchResultWithPostInfo { Self::affirm_and_maybe_schedule_instruction( origin, id, - portfolios.into_iter(), + portfolios.into_inner(), None ) } @@ -624,8 +626,8 @@ decl_module! { /// # Permissions /// * Portfolio #[weight = ::WeightInfo::withdraw_affirmation_input(None, portfolios.len() as u32)] - pub fn withdraw_affirmation(origin, id: InstructionId, portfolios: Vec) -> DispatchResultWithPostInfo { - Self::base_withdraw_affirmation(origin, id, portfolios, None) + pub fn withdraw_affirmation(origin, id: InstructionId, portfolios: BoundedBTreeSet) -> DispatchResultWithPostInfo { + Self::base_withdraw_affirmation(origin, id, portfolios.into_inner(), None) } /// Rejects an existing instruction. @@ -673,14 +675,14 @@ decl_module! { origin, id: InstructionId, receipt_details: Vec>, - portfolios: Vec, + portfolios: BoundedBTreeSet, number_of_assets: Option ) { Self::affirm_with_receipts_and_maybe_schedule_instruction( origin, id, receipt_details, - portfolios, + portfolios.into_inner(), number_of_assets ) .map_err(|e| e.error)?; @@ -701,13 +703,13 @@ decl_module! { pub fn affirm_instruction_with_count( origin, id: InstructionId, - portfolios: Vec, + portfolios: BoundedBTreeSet, number_of_assets: Option ) { Self::affirm_and_maybe_schedule_instruction( origin, id, - portfolios.into_iter(), + portfolios.into_inner(), number_of_assets ) .map_err(|e| e.error)?; @@ -750,10 +752,10 @@ decl_module! { pub fn withdraw_affirmation_with_count( origin, id: InstructionId, - portfolios: Vec, + portfolios: BoundedBTreeSet, number_of_assets: Option ) { - Self::base_withdraw_affirmation(origin, id, portfolios, number_of_assets) + Self::base_withdraw_affirmation(origin, id, portfolios.into_inner(), number_of_assets) .map_err(|e| e.error)?; } @@ -813,7 +815,7 @@ decl_module! { trade_date: Option, value_date: Option, legs: Vec, - portfolios: Vec, + portfolios: BoundedBTreeSet, instruction_memo: Option, mediators: BoundedBTreeSet, ) { @@ -828,11 +830,10 @@ decl_module! { instruction_memo, Some(mediators) )?; - let portfolios_set = portfolios.into_iter().collect::>(); Self::affirm_and_maybe_schedule_instruction( origin, instruction_id, - portfolios_set.into_iter(), + portfolios.into_inner(), None ) .map_err(|e| e.error)?; @@ -1133,11 +1134,10 @@ impl Module { fn unsafe_withdraw_instruction_affirmation( did: IdentityId, id: InstructionId, - portfolios: Vec, + portfolios: BTreeSet, secondary_key: Option<&SecondaryKey>, affirmation_count: Option, ) -> Result { - let portfolios = portfolios.into_iter().collect::>(); // checks custodianship of portfolios and affirmation status Self::ensure_portfolios_and_affirmation_status( id, @@ -1605,7 +1605,7 @@ impl Module { origin: ::RuntimeOrigin, instruction_id: InstructionId, receipts_details: Vec>, - portfolios: Vec, + portfolios: BTreeSet, affirmation_count: Option, ) -> Result { ensure!( @@ -1615,12 +1615,11 @@ impl Module { let (did, secondary_key, instruction_details) = Self::ensure_origin_perm_and_instruction_validity(origin, instruction_id, false)?; - let portfolios_set = portfolios.into_iter().collect::>(); // Verify portfolio custodianship and check if it is a counter party with a pending affirmation. Self::ensure_portfolios_and_affirmation_status( instruction_id, - &portfolios_set, + &portfolios, did, secondary_key.as_ref(), &[AffirmationStatus::Pending], @@ -1633,7 +1632,7 @@ impl Module { )?; // Lock tokens for all legs that are not of type [`Leg::OffChain`] - let filtered_legs = Self::filtered_legs(instruction_id, &portfolios_set); + let filtered_legs = Self::filtered_legs(instruction_id, &portfolios); // If the fee was estimated in advance, the input values must be at least equal to the actual values if let Some(affirmation_count) = affirmation_count { Self::ensure_valid_affirmation_count(&filtered_legs, &affirmation_count)? @@ -1645,7 +1644,7 @@ impl Module { // Casting is safe since `Self::ensure_portfolios_and_affirmation_status` is called let affirms_pending = InstructionAffirmsPending::get(instruction_id) - .saturating_sub(portfolios_set.len() as u64) + .saturating_sub(portfolios.len() as u64) .saturating_sub(receipts_details.len() as u64); InstructionAffirmsPending::insert(instruction_id, affirms_pending); @@ -1675,7 +1674,7 @@ impl Module { )); } - for portfolio in portfolios_set { + for portfolio in portfolios { UserAffirmations::insert(portfolio, instruction_id, AffirmationStatus::Affirmed); AffirmsReceived::insert(instruction_id, portfolio, AffirmationStatus::Affirmed); Self::deposit_event(RawEvent::InstructionAffirmed( @@ -1691,13 +1690,12 @@ impl Module { pub fn base_affirm_instruction( origin: ::RuntimeOrigin, id: InstructionId, - portfolios: impl Iterator, + portfolios: BTreeSet, affirmation_count: Option, ) -> Result { let (did, sk, _) = Self::ensure_origin_perm_and_instruction_validity(origin, id, false)?; - let portfolios_set = portfolios.collect::>(); // Provide affirmation to the instruction - Self::unsafe_affirm_instruction(did, id, portfolios_set, sk.as_ref(), affirmation_count) + Self::unsafe_affirm_instruction(did, id, portfolios, sk.as_ref(), affirmation_count) } /// Affirms all legs from the instruction of the given `id`, where `portfolios` are a counter party. @@ -1708,7 +1706,7 @@ impl Module { origin: ::RuntimeOrigin, id: InstructionId, receipt_details: Vec>, - portfolios: Vec, + portfolios: BTreeSet, affirmation_count: Option, ) -> DispatchResultWithPostInfo { let filtered_legs = Self::base_affirm_with_receipts( @@ -1742,7 +1740,7 @@ impl Module { pub fn affirm_and_maybe_schedule_instruction( origin: ::RuntimeOrigin, id: InstructionId, - portfolios: impl Iterator, + portfolios: BTreeSet, affirmation_count: Option, ) -> DispatchResultWithPostInfo { let filtered_legs = @@ -1770,7 +1768,7 @@ impl Module { origin: ::RuntimeOrigin, id: InstructionId, receipt: Option>, - portfolios: Vec, + portfolios: BTreeSet, caller_did: IdentityId, weight_meter: &mut WeightMeter, ) -> DispatchResult { @@ -1778,7 +1776,7 @@ impl Module { Some(receipt) => { Self::base_affirm_with_receipts(origin, id, vec![receipt], portfolios, None)? } - None => Self::base_affirm_instruction(origin, id, portfolios.into_iter(), None)?, + None => Self::base_affirm_instruction(origin, id, portfolios, None)?, }; Self::execute_settle_on_affirmation_instruction( id, @@ -1831,10 +1829,10 @@ impl Module { } /// Returns [`FilteredLegs`] where the orginal set is all legs in the instruction of the given - /// `id` and the subset of legs are all legs where the sender is in the given `portfolio_set`. - fn filtered_legs(id: InstructionId, portfolio_set: &BTreeSet) -> FilteredLegs { + /// `id` and the subset of legs are all legs where the sender is in the given `portfolio`. + fn filtered_legs(id: InstructionId, portfolio: &BTreeSet) -> FilteredLegs { let instruction_legs: Vec<(LegId, Leg)> = InstructionLegs::iter_prefix(&id).collect(); - FilteredLegs::filter_sender(instruction_legs, portfolio_set) + FilteredLegs::filter_sender(instruction_legs, portfolio) } fn get_instruction_asset_count(id: &InstructionId) -> AssetCount { @@ -2333,7 +2331,7 @@ impl Module { fn base_withdraw_affirmation( origin: T::RuntimeOrigin, id: InstructionId, - portfolios: Vec, + portfolios: BTreeSet, affirmation_count: Option, ) -> DispatchResultWithPostInfo { let (did, secondary_key, details) = @@ -2547,7 +2545,6 @@ impl Module { pub fn get_actual_weight(call: &Call) -> Option { match call { Call::affirm_instruction { id, portfolios } => { - let portfolios = portfolios.into_iter().cloned().collect::>(); let filtered_legs = Self::filtered_legs(*id, &portfolios); Some(Self::affirm_instruction_actual_weight( *filtered_legs.sender_asset_count(), @@ -2555,7 +2552,6 @@ impl Module { )) } Call::affirm_with_receipts { id, portfolios, .. } => { - let portfolios = portfolios.into_iter().cloned().collect::>(); let filtered_legs = Self::filtered_legs(*id, &portfolios); Some(Self::affirm_with_receipts_actual_weight( *filtered_legs.sender_asset_count(), @@ -2564,7 +2560,6 @@ impl Module { )) } Call::withdraw_affirmation { id, portfolios } => { - let portfolios = portfolios.into_iter().cloned().collect::>(); let filtered_legs = Self::filtered_legs(*id, &portfolios); Some(Self::withdraw_affirmation_actual_weight( *filtered_legs.sender_asset_count(), diff --git a/pallets/sto/src/lib.rs b/pallets/sto/src/lib.rs index 452b3d059..a6751b5cd 100644 --- a/pallets/sto/src/lib.rs +++ b/pallets/sto/src/lib.rs @@ -506,7 +506,7 @@ decl_module! { None )?; - let portfolios = vec![investment_portfolio, funding_portfolio]; + let portfolios = [investment_portfolio, funding_portfolio].iter().copied().collect::>(); Settlement::::affirm_and_execute_instruction( origin, instruction_id,