diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index e5297bd64f..7103b05152 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -122,7 +122,7 @@ use sp_runtime::{ traits::{AppVerify, One, Saturating}, DispatchResult, SaturatedConversion, }; -use sp_std::{cmp, mem, prelude::*}; +use sp_std::{cmp, collections::btree_set::BTreeSet, mem, prelude::*}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -2127,7 +2127,7 @@ impl Pallet { /// or removing parachains in bulk. pub(crate) struct ParachainsCache { // `None` here means the parachains list has not been accessed yet, nevermind modified. - parachains: Option>, + parachains: Option>, _config: PhantomData, } @@ -2136,32 +2136,29 @@ impl ParachainsCache { Self { parachains: None, _config: PhantomData } } - fn ensure_initialized(&mut self) -> &mut Vec { - self.parachains.get_or_insert_with(|| Parachains::::get()) + fn ensure_initialized(&mut self) -> &mut BTreeSet { + self.parachains + .get_or_insert_with(|| Parachains::::get().into_iter().collect()) } /// Adds the given para id to the list. pub fn add(&mut self, id: ParaId) { let parachains = self.ensure_initialized(); - if let Err(i) = parachains.binary_search(&id) { - parachains.insert(i, id); - } + parachains.insert(id); } /// Removes the given para id from the list of parachains. Does nothing if the id is not in the /// list. pub fn remove(&mut self, id: ParaId) { let parachains = self.ensure_initialized(); - if let Ok(i) = parachains.binary_search(&id) { - parachains.remove(i); - } + parachains.remove(&id); } } impl Drop for ParachainsCache { fn drop(&mut self) { if let Some(parachains) = self.parachains.take() { - Parachains::::put(¶chains); + Parachains::::put(parachains.into_iter().collect::>()); } } } diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index df639b495f..98233887b6 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -1767,3 +1767,77 @@ fn parakind_encodes_decodes_to_bool_serde() { let ser_false = serde_json::to_string(&false).unwrap(); assert_eq!(ser_false, ser_thread); } + +#[test] +fn parachains_cache_is_set() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let a = ParaId::from(111); + + let mut parachains_cache: ParachainsCache = ParachainsCache::new(); + + // Add element twice + parachains_cache.add(a); + parachains_cache.add(a); + + // Flush cache to storage + drop(parachains_cache); + + // In order after addition + assert_eq!(::Parachains::get(), vec![a]); + + let mut parachains_cache: ParachainsCache = ParachainsCache::new(); + + // Remove element twice + parachains_cache.remove(a); + parachains_cache.remove(a); + + // Flush cache to storage + drop(parachains_cache); + + // In order after removal + assert_eq!(::Parachains::get(), vec![]); + + let mut parachains_cache: ParachainsCache = ParachainsCache::new(); + + // Remove nonexisting element + parachains_cache.remove(a); + assert_storage_noop!(drop(parachains_cache)); + assert_eq!(::Parachains::get(), vec![]); + }); +} + +#[test] +fn parachains_cache_preserves_order() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let a = ParaId::from(111); + let b = ParaId::from(222); + let c = ParaId::from(333); + let d = ParaId::from(444); + + let mut parachains_cache: ParachainsCache = ParachainsCache::new(); + + // Add in mixed order + parachains_cache.add(b); + parachains_cache.add(c); + parachains_cache.add(a); + parachains_cache.add(d); + + // Flush cache to storage + drop(parachains_cache); + + // In order after addition + assert_eq!(::Parachains::get(), vec![a, b, c, d]); + + let mut parachains_cache: ParachainsCache = ParachainsCache::new(); + + // Remove 2 elements + parachains_cache.remove(b); + parachains_cache.remove(d); + + // Flush cache to storage + drop(parachains_cache); + + // In order after removal + assert_eq!(::Parachains::get(), vec![a, c]); + }); +}