From 5463f5af8877bc829faa1f9ee73b59604dfb9b3e Mon Sep 17 00:00:00 2001
From: Xiliang Chen <xlchen1291@gmail.com>
Date: Fri, 21 May 2021 22:26:59 +1200
Subject: [PATCH] refactor oracle to remove members (#502)

* no longer need Members

* fix warning

* fix tests
---
 oracle/src/lib.rs   | 61 ++++++++-------------------------------------
 oracle/src/mock.rs  | 22 +++++++++-------
 oracle/src/tests.rs |  1 +
 3 files changed, 24 insertions(+), 60 deletions(-)

diff --git a/oracle/src/lib.rs b/oracle/src/lib.rs
index e17708f..b061633 100644
--- a/oracle/src/lib.rs
+++ b/oracle/src/lib.rs
@@ -11,10 +11,8 @@
 //! offchain data. The raw values can be combined to provide an aggregated
 //! value.
 //!
-//! The data is valid only if feeded by an authorized operator. This module
-//! implements `frame_support::traits::InitializeMembers` and `frame_support::
-//! traits::ChangeMembers`, to provide a way to manage operators membership.
-//! Typically it could be leveraged to `pallet_membership` in FRAME.
+//! The data is valid only if feeded by an authorized operator.
+//! `pallet_membership` in FRAME can be used to as source of `T::Members`.
 
 #![cfg_attr(not(feature = "std"), no_std)]
 // Disable the following two lints since they originate from an external macro (namely decl_storage)
@@ -29,7 +27,7 @@ use serde::{Deserialize, Serialize};
 use frame_support::{
 	ensure,
 	pallet_prelude::*,
-	traits::{ChangeMembers, Get, InitializeMembers, Time},
+	traits::{ChangeMembers, Get, SortedMembers, Time},
 	weights::{Pays, Weight},
 	Parameter,
 };
@@ -86,6 +84,9 @@ pub mod module {
 		/// The root operator account id, record all sudo feeds on this account.
 		type RootOperatorAccountId: Get<Self::AccountId>;
 
+		/// Oracle operators.
+		type Members: SortedMembers<Self::AccountId>;
+
 		/// Weight information for extrinsics in this module.
 		type WeightInfo: WeightInfo;
 	}
@@ -128,36 +129,6 @@ pub mod module {
 	pub(crate) type HasDispatched<T: Config<I>, I: 'static = ()> =
 		StorageValue<_, OrderedSet<T::AccountId>, ValueQuery>;
 
-	// TODO: this shouldn't be required https://github.com/paritytech/substrate/issues/6041
-	/// The current members of the collective. This is stored sorted (just by
-	/// value).
-	#[pallet::storage]
-	#[pallet::getter(fn members)]
-	pub type Members<T: Config<I>, I: 'static = ()> = StorageValue<_, OrderedSet<T::AccountId>, ValueQuery>;
-
-	#[pallet::genesis_config]
-	pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
-		pub members: OrderedSet<T::AccountId>,
-		pub phantom: sp_std::marker::PhantomData<I>,
-	}
-
-	#[cfg(feature = "std")]
-	impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
-		fn default() -> Self {
-			GenesisConfig {
-				members: Default::default(),
-				phantom: Default::default(),
-			}
-		}
-	}
-
-	#[pallet::genesis_build]
-	impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> {
-		fn build(&self) {
-			<Members<T, I>>::put(self.members.clone());
-		}
-	}
-
 	#[pallet::pallet]
 	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
 
@@ -194,8 +165,7 @@ pub mod module {
 
 impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	pub fn read_raw_values(key: &T::OracleKey) -> Vec<TimestampedValueOf<T, I>> {
-		Self::members()
-			.0
+		T::Members::sorted_members()
 			.iter()
 			.chain(vec![T::RootOperatorAccountId::get()].iter())
 			.filter_map(|x| Self::raw_values(x, key))
@@ -248,7 +218,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	fn do_feed_values(who: T::AccountId, values: Vec<(T::OracleKey, T::OracleValue)>) -> DispatchResult {
 		// ensure feeder is authorized
 		ensure!(
-			Self::members().contains(&who) || who == T::RootOperatorAccountId::get(),
+			T::Members::contains(&who) || who == T::RootOperatorAccountId::get(),
 			Error::<T, I>::NoPermission
 		);
 
@@ -274,24 +244,13 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	}
 }
 
-impl<T: Config<I>, I: 'static> InitializeMembers<T::AccountId> for Pallet<T, I> {
-	fn initialize_members(members: &[T::AccountId]) {
-		if !members.is_empty() {
-			assert!(Members::<T, I>::get().0.is_empty(), "Members are already initialized!");
-			Members::<T, I>::put(OrderedSet::from_sorted_set(members.into()));
-		}
-	}
-}
-
 impl<T: Config<I>, I: 'static> ChangeMembers<T::AccountId> for Pallet<T, I> {
-	fn change_members_sorted(_incoming: &[T::AccountId], outgoing: &[T::AccountId], new: &[T::AccountId]) {
-		// remove session keys and its values
+	fn change_members_sorted(_incoming: &[T::AccountId], outgoing: &[T::AccountId], _new: &[T::AccountId]) {
+		// remove values
 		for removed in outgoing {
 			RawValues::<T, I>::remove_prefix(removed);
 		}
 
-		Members::<T, I>::put(OrderedSet::from_sorted_set(new.into()));
-
 		// not bothering to track which key needs recompute, just update all
 		IsUpdated::<T, I>::remove_all();
 	}
diff --git a/oracle/src/mock.rs b/oracle/src/mock.rs
index 569dcdc..6ab658c 100644
--- a/oracle/src/mock.rs
+++ b/oracle/src/mock.rs
@@ -2,7 +2,7 @@
 
 use super::*;
 
-use frame_support::{construct_runtime, parameter_types};
+use frame_support::{construct_runtime, parameter_types, traits::SortedMembers};
 use sp_core::H256;
 use sp_runtime::{
 	testing::Header,
@@ -71,6 +71,15 @@ parameter_types! {
 	pub const MinimumCount: u32 = 3;
 	pub const ExpiresIn: u32 = 600;
 	pub const RootOperatorAccountId: AccountId = 4;
+	pub static OracleMembers: Vec<AccountId> = vec![1, 2, 3];
+}
+
+pub struct Members;
+
+impl SortedMembers<AccountId> for Members {
+	fn sorted_members() -> Vec<AccountId> {
+		OracleMembers::get()
+	}
 }
 
 impl Config for Test {
@@ -81,6 +90,7 @@ impl Config for Test {
 	type OracleKey = Key;
 	type OracleValue = Value;
 	type RootOperatorAccountId = RootOperatorAccountId;
+	type Members = Members;
 	type WeightInfo = ();
 }
 
@@ -94,20 +104,14 @@ construct_runtime!(
 		UncheckedExtrinsic = UncheckedExtrinsic,
 	{
 		System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
-		ModuleOracle: oracle::{Pallet, Storage, Call, Config<T>, Event<T>},
+		ModuleOracle: oracle::{Pallet, Storage, Call, Event<T>},
 	}
 );
 
 // This function basically just builds a genesis storage key/value store
 // according to our desired mockup.
 pub fn new_test_ext() -> sp_io::TestExternalities {
-	let mut storage = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
-
-	let _ = oracle::GenesisConfig::<Test> {
-		members: vec![1, 2, 3].into(),
-		phantom: Default::default(),
-	}
-	.assimilate_storage(&mut storage);
+	let storage = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
 
 	let mut t: sp_io::TestExternalities = storage.into();
 
diff --git a/oracle/src/tests.rs b/oracle/src/tests.rs
index 79f0fcc..d5a8fae 100644
--- a/oracle/src/tests.rs
+++ b/oracle/src/tests.rs
@@ -237,6 +237,7 @@ fn get_all_values_should_work() {
 #[test]
 fn change_member_should_work() {
 	new_test_ext().execute_with(|| {
+		OracleMembers::set(vec![2, 3, 4]);
 		<ModuleOracle as ChangeMembers<AccountId>>::change_members_sorted(&[4], &[1], &[2, 3, 4]);
 		assert_noop!(
 			ModuleOracle::feed_values(Origin::signed(1), vec![(50, 1000)]),
-- 
GitLab