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