From b61db85f341c27a2bfae60aa46704087637a79dd Mon Sep 17 00:00:00 2001
From: Ermal Kaleci <ermalkaleci@gmail.com>
Date: Fri, 17 Apr 2020 00:17:27 +0200
Subject: [PATCH] oracle get_all_values rpc method (#141)

* oracle get_all_values rpc method

* update import
---
 oracle/rpc/runtime-api/Cargo.toml |  4 ++-
 oracle/rpc/runtime-api/src/lib.rs |  2 ++
 oracle/rpc/src/lib.rs             | 24 ++++++++++++--
 oracle/src/lib.rs                 |  9 +++++-
 oracle/src/tests.rs               | 53 +++++++++++++++++++++++++++++++
 5 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/oracle/rpc/runtime-api/Cargo.toml b/oracle/rpc/runtime-api/Cargo.toml
index 84a2ec1..b68ee44 100644
--- a/oracle/rpc/runtime-api/Cargo.toml
+++ b/oracle/rpc/runtime-api/Cargo.toml
@@ -7,10 +7,12 @@ edition = "2018"
 [dependencies]
 codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] }
 sp-api = { default-features = false, version = "2.0.0-alpha.6" }
+sp-std = { default-features = false, version = "2.0.0-alpha.6" }
 
 [features]
 default = ["std"]
 std = [
-	"sp-api/std",
 	"codec/std",
+	"sp-api/std",
+	"sp-std/std"
 ]
diff --git a/oracle/rpc/runtime-api/src/lib.rs b/oracle/rpc/runtime-api/src/lib.rs
index 2dd6ee9..6bfe62b 100644
--- a/oracle/rpc/runtime-api/src/lib.rs
+++ b/oracle/rpc/runtime-api/src/lib.rs
@@ -3,6 +3,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use codec::Codec;
+use sp_std::prelude::Vec;
 
 sp_api::decl_runtime_apis! {
 	pub trait OracleApi<Key, Value> where
@@ -10,5 +11,6 @@ sp_api::decl_runtime_apis! {
 		Value: Codec,
 	{
 		fn get_value(key: Key) -> Option<Value>;
+		fn get_all_values() -> Vec<(Key, Option<Value>)>;
 	}
 }
diff --git a/oracle/rpc/src/lib.rs b/oracle/rpc/src/lib.rs
index eb2bde8..ce2e048 100644
--- a/oracle/rpc/src/lib.rs
+++ b/oracle/rpc/src/lib.rs
@@ -1,17 +1,21 @@
-pub use self::gen_client::Client as OracleClient;
+use std::sync::Arc;
+
 use codec::Codec;
 use jsonrpc_core::{Error as RpcError, ErrorCode, Result};
 use jsonrpc_derive::rpc;
-pub use orml_oracle_rpc_runtime_api::OracleApi as OracleRuntimeApi;
 use sp_api::ProvideRuntimeApi;
 use sp_blockchain::HeaderBackend;
 use sp_runtime::{generic::BlockId, traits::Block as BlockT};
-use std::sync::Arc;
+
+pub use orml_oracle_rpc_runtime_api::OracleApi as OracleRuntimeApi;
+pub use self::gen_client::Client as OracleClient;
 
 #[rpc]
 pub trait OracleApi<BlockHash, Key, Value> {
 	#[rpc(name = "oracle_getValue")]
 	fn get_value(&self, key: Key, at: Option<BlockHash>) -> Result<Option<Value>>;
+	#[rpc(name = "oracle_getAllValues")]
+	fn get_all_values(&self, at: Option<BlockHash>) -> Result<Vec<(Key, Option<Value>)>>;
 }
 
 /// A struct that implements the [`OracleApi`].
@@ -63,4 +67,18 @@ where
 			})
 			.into()
 	}
+
+	fn get_all_values(&self, at: Option<<Block as BlockT>::Hash>) -> Result<Vec<(Key, Option<Value>)>> {
+		let api = self.client.runtime_api();
+		let at = BlockId::hash(at.unwrap_or_else(||
+			// If the block hash is not supplied assume the best block.
+			self.client.info().best_hash));
+		api.get_all_values(&at)
+			.map_err(|e| RpcError {
+				code: ErrorCode::ServerError(Error::RuntimeError.into()),
+				message: "Unable to get all values.".into(),
+				data: Some(format!("{:?}", e).into()),
+			})
+			.into()
+	}
 }
diff --git a/oracle/src/lib.rs b/oracle/src/lib.rs
index 18fba5e..4a29ff1 100644
--- a/oracle/src/lib.rs
+++ b/oracle/src/lib.rs
@@ -14,7 +14,7 @@ use frame_support::{
 	ensure,
 	traits::Time,
 	weights::{DispatchClass, FunctionOf, TransactionPriority},
-	IsSubType, Parameter,
+	IsSubType, IterableStorageMap, Parameter,
 };
 pub use operator_provider::OperatorProvider;
 use sp_runtime::{
@@ -136,6 +136,13 @@ impl<T: Trait> Module<T> {
 		}
 	}
 
+	pub fn get_all_values() -> Vec<(T::OracleKey, Option<TimestampedValueOf<T>>)> {
+		<Values<T>>::iter()
+			.map(|(key, _)| key)
+			.map(|key| (key.clone(), Self::get_no_op(&key)))
+			.collect()
+	}
+
 	fn combined(key: &T::OracleKey) -> Option<TimestampedValueOf<T>> {
 		let values = Self::read_raw_values(key);
 		T::CombineData::combine_data(key, values, Self::values(key))
diff --git a/oracle/src/tests.rs b/oracle/src/tests.rs
index 1737885..443f140 100644
--- a/oracle/src/tests.rs
+++ b/oracle/src/tests.rs
@@ -206,3 +206,56 @@ fn multiple_calls_should_fail() {
 		assert_ok!(ModuleOracle::feed_value(Origin::signed(1), 1, 1200));
 	});
 }
+
+#[test]
+fn get_all_values_should_work() {
+	new_test_ext().execute_with(|| {
+		Timestamp::set_timestamp(12345);
+
+		let eur: u32 = 1;
+		let jpy: u32 = 2;
+
+		assert_eq!(ModuleOracle::get_all_values(), vec![]);
+
+		// feed eur & jpy
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(1), eur, 1300));
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(2), eur, 1000));
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(3), jpy, 9000));
+
+		// not enough eur & jpy prices
+		assert_eq!(ModuleOracle::get(&eur), None);
+		assert_eq!(ModuleOracle::get(&jpy), None);
+		assert_eq!(ModuleOracle::get_all_values(), vec![]);
+
+		// finalize block
+		<ModuleOracle as OnFinalize<u64>>::on_finalize(1);
+
+		// feed eur & jpy
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(3), eur, 1200));
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(1), jpy, 8000));
+
+		// enough eur prices
+		let eur_price = Some(TimestampedValue {
+			value: 1200,
+			timestamp: 12345,
+		});
+		assert_eq!(ModuleOracle::get(&eur), eur_price);
+
+		// not enough jpy prices
+		assert_eq!(ModuleOracle::get(&jpy), None);
+
+		assert_eq!(ModuleOracle::get_all_values(), vec![(eur, eur_price)]);
+
+		// feed jpy
+		assert_ok!(ModuleOracle::feed_value(Origin::signed(2), jpy, 7000));
+
+		// enough jpy prices
+		let jpy_price = Some(TimestampedValue {
+			value: 8000,
+			timestamp: 12345,
+		});
+		assert_eq!(ModuleOracle::get(&jpy), jpy_price);
+
+		assert_eq!(ModuleOracle::get_all_values(), vec![(eur, eur_price), (jpy, jpy_price)]);
+	});
+}
-- 
GitLab