Skip to content
Snippets Groups Projects
lib.rs 3.48 KiB
Newer Older
  • Learn to ignore specific revisions
  • Bryan Chen's avatar
    Bryan Chen committed
    #![cfg_attr(not(feature = "std"), no_std)]
    
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    mod default_combine_data;
    mod mock;
    mod operator_provider;
    mod tests;
    mod timestamped_value;
    
    pub use default_combine_data::DefaultCombineData;
    pub use operator_provider::OperatorProvider;
    
    use palette_support::{
    	decl_error, decl_event, decl_module, decl_storage, dispatch::Result, ensure, traits::Time, Parameter,
    };
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    use rstd::{prelude::*, result, vec};
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    use sr_primitives::traits::Member;
    
    // FIXME: `pallet/palette-` prefix should be used for all pallet modules, but currently `palette_system`
    // would cause compiling error in `decl_module!` and `construct_runtime!`
    // #3295 https://github.com/paritytech/substrate/issues/3295
    pub use orml_traits::{CombineData, OnNewData};
    use palette_system::{self as system, ensure_signed};
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    pub use timestamped_value::TimestampedValue;
    
    type MomentOf<T> = <<T as Trait>::Time as Time>::Moment;
    pub type TimestampedValueOf<T> = TimestampedValue<<T as Trait>::Value, MomentOf<T>>;
    
    Bryan Chen's avatar
    Bryan Chen committed
    
    
    pub trait Trait: palette_system::Trait {
    	type Event: From<Event<Self>> + Into<<Self as palette_system::Trait>::Event>;
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    	type OnNewData: OnNewData<Self::Key, Self::Value>;
    	type OperatorProvider: OperatorProvider<Self::AccountId>;
    	type CombineData: CombineData<Self::Key, TimestampedValueOf<Self>>;
    	type Time: Time;
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    	type Key: Parameter + Member;
    	type Value: Parameter + Member + Ord;
    
    Bryan Chen's avatar
    Bryan Chen committed
    }
    
    decl_storage! {
    	trait Store for Module<T: Trait> as Oracle {
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    		pub RawValues get(raw_values): double_map T::Key, blake2_256(T::AccountId) => Option<TimestampedValueOf<T>>;
    		pub HasUpdate get(has_update): map T::Key => bool;
    		pub Values get(values): map T::Key => Option<TimestampedValueOf<T>>;
    	}
    }
    
    decl_error! {
    	// Oracle module errors
    	pub enum Error {
    		NoPermission,
    	}
    }
    
    decl_module! {
    	pub struct Module<T: Trait> for enum Call where origin: T::Origin {
    		fn deposit_event() = default;
    
    Bryan Chen's avatar
    Bryan Chen committed
    
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    		pub fn feed_value(origin, key: T::Key, value: T::Value) -> Result {
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    			let who = ensure_signed(origin)?;
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    			Self::_feed_values(who, vec![(key, value)]).map_err(|e| e.into())
    		}
    
    		pub fn feed_values(origin, values: Vec<(T::Key, T::Value)>) -> Result {
    			let who = ensure_signed(origin)?;
    			Self::_feed_values(who, values).map_err(|e| e.into())
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    		}
    
    Bryan Chen's avatar
    Bryan Chen committed
    	}
    }
    
    decl_event!(
    	pub enum Event<T> where
    
    		<T as palette_system::Trait>::AccountId,
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    		<T as Trait>::Key,
    		<T as Trait>::Value,
    
    Bryan Chen's avatar
    Bryan Chen committed
    	{
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    		/// New feed data is submitted (sender, values)
    		NewFeedData(AccountId, Vec<(Key, Value)>),
    
    Bryan Chen's avatar
    Bryan Chen committed
    	}
    );
    
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    impl<T: Trait> Module<T> {
    	pub fn read_raw_values(key: &T::Key) -> Vec<TimestampedValueOf<T>> {
    		T::OperatorProvider::operators()
    			.iter()
    			.filter_map(|x| <RawValues<T>>::get(key, x))
    			.collect()
    	}
    
    Bryan Chen's avatar
    Bryan Chen committed
    
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    	pub fn get(key: &T::Key) -> Option<TimestampedValueOf<T>> {
    		if <HasUpdate<T>>::take(key) {
    			let values = Self::read_raw_values(key);
    			let timestamped = T::CombineData::combine_data(key, values, <Values<T>>::get(key))?;
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    			<Values<T>>::insert(key, timestamped.clone());
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    			return Some(timestamped);
    		}
    		<Values<T>>::get(key)
    
    Bryan Chen's avatar
    Bryan Chen committed
    	}
    }
    
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    impl<T: Trait> Module<T> {
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    	fn _feed_values(who: T::AccountId, values: Vec<(T::Key, T::Value)>) -> result::Result<(), Error> {
    
    Ermal Kaleci's avatar
    Ermal Kaleci committed
    		ensure!(T::OperatorProvider::can_feed_data(&who), Error::NoPermission);
    
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    		let now = T::Time::now();
    
    		for (key, value) in &values {
    			let timestamped = TimestampedValue {
    				value: value.clone(),
    				timestamp: now,
    			};
    			<RawValues<T>>::insert(&key, &who, timestamped);
    			<HasUpdate<T>>::insert(&key, true);
    
    			T::OnNewData::on_new_data(&key, &value);
    		}
    
    Xiliang Chen's avatar
    Xiliang Chen committed
    		Self::deposit_event(RawEvent::NewFeedData(who, values));