1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use frame_support::traits::{Get, Time};
use orml_traits::CombineData;
use sp_std::{marker, prelude::*};

use crate::{MomentOf, TimestampedValueOf, Trait};

/// Sort by value and returns median timestamped value.
/// Returns prev_value if not enough valid values.
pub struct DefaultCombineData<T, MinimumCount, ExpiresIn>(marker::PhantomData<(T, MinimumCount, ExpiresIn)>);

impl<T, MinimumCount, ExpiresIn> CombineData<T::OracleKey, TimestampedValueOf<T>>
	for DefaultCombineData<T, MinimumCount, ExpiresIn>
where
	T: Trait,
	MinimumCount: Get<u32>,
	ExpiresIn: Get<MomentOf<T>>,
{
	fn combine_data(
		_key: &T::OracleKey,
		values: Vec<TimestampedValueOf<T>>,
		prev_value: Option<TimestampedValueOf<T>>,
	) -> Option<TimestampedValueOf<T>> {
		let expires_in = ExpiresIn::get();
		let now = T::Time::now();
		let mut valid_values = values
			.into_iter()
			.filter(|x| x.timestamp + expires_in > now)
			.collect::<Vec<TimestampedValueOf<T>>>();

		let count = valid_values.len() as u32;
		let minimum_count = MinimumCount::get();
		if count < minimum_count {
			return prev_value;
		}

		valid_values.sort_by(|a, b| a.value.cmp(&b.value));

		let median_index = count / 2;
		Some(valid_values[median_index as usize].clone())
	}
}