Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add whitelist of trusted exchange rate oracles #24

Merged
merged 6 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion teeracle/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,40 @@ benchmarks! {
TEST4_SETUP.cert.to_vec(),
URL.to_vec()
).unwrap();

let mrenclave = Teerex::<T>::enclave(1).mr_enclave;
Exchange::<T>::add_to_whitelist(RawOrigin::Root.into(), mrenclave);

}: _(RawOrigin::Signed(signer), currency, Some(rate))
verify {
assert_eq!(Exchange::<T>::exchange_rate("usd".as_bytes().to_owned()), U32F32::from_num(43.65));
}

add_to_whitelist {
let mrenclave = TEST4_MRENCLAVE;

}: _(RawOrigin::Root, mrenclave)
verify {
assert_eq!(Exchange::<T>::whitelisted_oracle_count(), 1, "mrenclave not added to whitelist")
}

remove_from_whitelist {
let mrenclave = TEST4_MRENCLAVE;
Exchange::<T>::add_to_whitelist(RawOrigin::Root.into(), mrenclave);

}: _(RawOrigin::Root, mrenclave)
verify {
assert_eq!(Exchange::<T>::whitelisted_oracle_count(), 0, "mrenclave not removed from whitelist")
}

clear_whitelist {
ensure_not_skipping_ra_check();
let mrenclave = TEST4_MRENCLAVE;
Exchange::<T>::add_to_whitelist(RawOrigin::Root.into(), mrenclave);

}: _(RawOrigin::Root)
verify {
assert_eq!(Exchange::<T>::whitelisted_oracle_count(), 0, "whitelist not cleared")
}
}

#[cfg(test)]
Expand Down
61 changes: 59 additions & 2 deletions teeracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use substrate_fixed::types::U32F32;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_support::{pallet_prelude::*, WeakBoundedVec};
use frame_system::pallet_prelude::*;
use sp_std::prelude::*;
use teeracle_primitives::*;
Expand All @@ -51,31 +51,74 @@ pub mod pallet {
/// The overarching event type.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type WeightInfo: WeightInfo;
/// Max number of whitelisted oracles allowed
#[pallet::constant]
type MaxOracles: Get<u32>;
}

/// Exchange rates chain's cryptocurrency/currency
#[pallet::storage]
#[pallet::getter(fn exchange_rate)]
pub(super) type ExchangeRates<T> =
pub(super) type ExchangeRates<T: Config> =
StorageMap<_, Blake2_128Concat, CurrencyString, ExchangeRate, ValueQuery>;

/// whitelist of trusted exchange rate oracles
#[pallet::storage]
#[pallet::getter(fn whitelist)]
pub(super) type Whitelist<T: Config> =
StorageValue<_, WeakBoundedVec<[u8; 32], T::MaxOracles>, ValueQuery>;

echevrier marked this conversation as resolved.
Show resolved Hide resolved
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// The exchange rate of currency was set/updated. \[currency], [new value\]
ExchangeRateUpdated(CurrencyString, Option<ExchangeRate>),
ExchangeRateDeleted(CurrencyString),
AddedToWhitelist([u8; 32]),
RemovedFromWhitelist([u8; 32]),
OracleWhitelistCleared,
}

#[pallet::error]
pub enum Error<T> {
InvalidCurrency,
/// Too many oracles in the whitelist.
TooManyOracles,
echevrier marked this conversation as resolved.
Show resolved Hide resolved
NonWhitelistedOracle,
AlreadyWhitelistedOracle,
UntrustedOracle,
echevrier marked this conversation as resolved.
Show resolved Hide resolved
}

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(<T as Config>::WeightInfo::add_to_whitelist())]
pub fn add_to_whitelist(origin: OriginFor<T>, mrenclave: [u8; 32]) -> DispatchResult {
ensure_root(origin)?;
ensure!(!Self::is_whitelisted(mrenclave), <Error<T>>::AlreadyWhitelistedOracle);
<Whitelist<T>>::try_append(mrenclave).map_err(|_| Error::<T>::TooManyOracles)?;
Self::deposit_event(Event::AddedToWhitelist(mrenclave));
Ok(())
}
#[pallet::weight(<T as Config>::WeightInfo::remove_from_whitelist())]
pub fn remove_from_whitelist(origin: OriginFor<T>, mrenclave: [u8; 32]) -> DispatchResult {
ensure_root(origin)?;
ensure!(Self::is_whitelisted(mrenclave), <Error<T>>::NonWhitelistedOracle);
Whitelist::<T>::mutate(|mrenclaves| mrenclaves.retain(|m| *m != mrenclave));
Self::deposit_event(Event::RemovedFromWhitelist(mrenclave));
Ok(())
}

#[pallet::weight(<T as Config>::WeightInfo::clear_whitelist())]
pub fn clear_whitelist(origin: OriginFor<T>) -> DispatchResult {
echevrier marked this conversation as resolved.
Show resolved Hide resolved
ensure_root(origin)?;
<Whitelist<T>>::kill();
Self::deposit_event(Event::OracleWhitelistCleared);
Ok(())
}

#[pallet::weight(<T as Config>::WeightInfo::update_exchange_rate())]
pub fn update_exchange_rate(
origin: OriginFor<T>,
Expand All @@ -84,6 +127,11 @@ pub mod pallet {
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
<pallet_teerex::Module<T>>::is_registered_enclave(&sender)?;
let sender_index = <pallet_teerex::Module<T>>::enclave_index(sender);
ensure!(
Self::is_whitelisted(<pallet_teerex::Module<T>>::enclave(sender_index).mr_enclave),
<Error<T>>::UntrustedOracle
);
if new_value.is_none() || new_value == Some(U32F32::from_num(0)) {
log::info!("Delete exchange rate : {:?}", new_value);
ExchangeRates::<T>::mutate_exists(currency.clone(), |rate| *rate = None);
Expand All @@ -97,6 +145,15 @@ pub mod pallet {
}
}
}
impl<T: Config> Pallet<T> {
fn is_whitelisted(mrenclave: [u8; 32]) -> bool {
Self::whitelist().iter().any(|m| *m == mrenclave)
echevrier marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn whitelisted_oracle_count() -> u32 {
echevrier marked this conversation as resolved.
Show resolved Hide resolved
Self::whitelist().len() as u32
}
}

mod benchmarking;
#[cfg(test)]
Expand Down
2 changes: 2 additions & 0 deletions teeracle/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ impl timestamp::Config for Test {
parameter_types! {
pub const MomentsPerDay: u64 = 86_400_000; // [ms/d]
pub const MaxSilenceTime: u64 = 172_800_000; // 48h
pub const MaxOracles: u32 = 2;
echevrier marked this conversation as resolved.
Show resolved Hide resolved
}

impl pallet_teerex::Config for Test {
Expand All @@ -133,6 +134,7 @@ impl pallet_teerex::Config for Test {
impl Config for Test {
type Event = Event;
type WeightInfo = ();
type MaxOracles = MaxOracles;
}

// This function basically just builds a genesis storage key/value store according to
Expand Down
Loading