diff --git a/Cargo.lock b/Cargo.lock index 58a267efe53..ed62c2075e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3811,7 +3811,6 @@ dependencies = [ "pallet-oracle", "pallet-randomness-collective-flip", "pallet-sudo", - "pallet-template", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -4140,20 +4139,6 @@ dependencies = [ "sp-std 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", ] -[[package]] -name = "pallet-template" -version = "3.0.0" -dependencies = [ - "frame-benchmarking", - "frame-support 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", - "frame-system 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", - "parity-scale-codec", - "serde", - "sp-core 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", - "sp-io 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", - "sp-runtime 3.0.0 (git+https://github.com/paritytech/substrate.git?rev=d6c33e7ec313f9bd5e319dc0a5a3ace5543f9617)", -] - [[package]] name = "pallet-timestamp" version = "3.0.0" diff --git a/pallets/oracle/src/lib.rs b/pallets/oracle/src/lib.rs index 695c8eb31b2..b4aab414199 100644 --- a/pallets/oracle/src/lib.rs +++ b/pallets/oracle/src/lib.rs @@ -92,6 +92,7 @@ pub mod pallet { type RequestCost: Get>; type RewardAmount: Get>; type SlashAmount: Get>; + type MaxAnswerBound: Get; } #[derive(Encode, Decode, Default, Debug, PartialEq)] @@ -229,6 +230,9 @@ pub mod pallet { UnsetController, ControllerUsed, SignerUsed, + AvoidPanic, + ExceedMaxAnswers, + InvalidMinAnswers } #[pallet::hooks] @@ -244,12 +248,17 @@ pub mod pallet { PrePrices::::insert(i, pre_prices.clone()); } if pre_prices.len() as u64 >= asset_info.min_answers { - let price = Self::get_median_price(&pre_prices); + let mut slice = pre_prices; + // check max answer + if slice.len() as u64 > asset_info.max_answers { + slice = slice[0 .. asset_info.max_answers as usize].to_vec(); + } + let price = Self::get_median_price(&slice); let set_price = Price { price, block }; Prices::::insert(i, set_price); Requested::::insert(i, false); PrePrices::::remove(i); - Self::handle_payout(&pre_prices, price, i); + Self::handle_payout(&slice, price, i); } } 0 @@ -274,6 +283,8 @@ pub mod pallet { max_answers: u64 ) -> DispatchResultWithPostInfo { T::AddOracle::ensure_origin(origin)?; + ensure!(max_answers <= T::MaxAnswerBound::get(), Error::::ExceedMaxAnswers); + ensure!(min_answers > 0, Error::::InvalidMinAnswers); let asset_info = AssetInfo { threshold, min_answers, @@ -498,6 +509,7 @@ pub mod pallet { .collect(); numbers.sort(); let mid = numbers.len() / 2; + // TODO maybe check length numbers[mid] } @@ -630,9 +642,7 @@ pub mod pallet { } _ => return None, }; - - let exp = price.fraction_length.checked_sub(2).unwrap_or(0); - Some(price.integer as u64 * 100 + (price.fraction / 10_u64.pow(exp)) as u64) + Some(price.integer as u64) } } } diff --git a/pallets/oracle/src/mock.rs b/pallets/oracle/src/mock.rs index 5161e2508d1..56c08ab2ce5 100644 --- a/pallets/oracle/src/mock.rs +++ b/pallets/oracle/src/mock.rs @@ -87,6 +87,7 @@ parameter_types! { pub const RequestCost: u64 = 1; pub const RewardAmount: u64 = 5; pub const SlashAmount: u64 = 5; + pub const MaxAnswerBound: u64 = 5; } @@ -135,6 +136,7 @@ impl pallet_oracle::Config for Test { type RequestCost = RequestCost; type RewardAmount = RewardAmount; type SlashAmount = SlashAmount; + type MaxAnswerBound = MaxAnswerBound; } // Build genesis storage according to the mock runtime. diff --git a/pallets/oracle/src/tests.rs b/pallets/oracle/src/tests.rs index c195371d482..97a880eae17 100644 --- a/pallets/oracle/src/tests.rs +++ b/pallets/oracle/src/tests.rs @@ -45,6 +45,22 @@ fn add_asset_and_info() { Oracle::add_asset_and_info(Origin::signed(account_1), 1, Percent::from_percent(80), 3, 5), BadOrigin ); + + assert_noop!(Oracle::add_asset_and_info( + Origin::signed(account_2), + 1, + Percent::from_percent(80), + 3, + 6, + ), Error::::ExceedMaxAnswers); + + assert_noop!(Oracle::add_asset_and_info( + Origin::signed(account_2), + 1, + Percent::from_percent(80), + 0, + 5, + ), Error::::InvalidMinAnswers); }); } @@ -529,6 +545,36 @@ fn on_init_prune_scenerios() { }); } +#[test] +fn on_init_over_max_answers() { + new_test_ext().execute_with(|| { + // add and request oracle id + let account_2 = get_account_2(); + assert_ok!(Oracle::add_asset_and_info( + Origin::signed(account_2), + 0, + Percent::from_percent(80), + 1, + 2, + )); + let account_1: AccountId = Default::default(); + assert_ok!(Oracle::do_request_price(&account_1, 0)); + // set prices into storage + let account_1: AccountId = Default::default(); + for i in 0..5 { + let price = i as u64 + 100u64; + add_price_storage(price, 0, account_1, 0); + } + // all pruned + Oracle::on_initialize(0); + // price prunes all but first 2 answers, median went from 102 to 101 + let price = Price { price: 101, block: 0 }; + assert_eq!(Oracle::prices(0), price); + assert_eq!(Oracle::pre_prices(0).len(), 0); + +}); +} + #[test] fn prune_old_edgecase() { new_test_ext().execute_with(|| { @@ -649,10 +695,8 @@ fn should_submit_signed_transaction_on_chain() { #[test] fn parse_price_works() { let test_data = vec![ - ("{\"USD\":6536.92}", Some(653692)), - ("{\"USD\":65.92}", Some(6592)), - ("{\"USD\":6536.924565}", Some(653692)), - ("{\"USD\":6536}", Some(653600)), + ("{\"USD\":6536.92}", Some(6536)), + ("{\"USD\":650000000}", Some(650000000)), ("{\"USD2\":6536}", None), ("{\"USD\":\"6432\"}", None), ]; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 4c693699350..c9b4679ccff 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -6,7 +6,7 @@ version = '2.0.0' [dependencies.pallet-cfgeneric] -# import our generic pallet +# import our generic pallet default-features = false path = "../pallets/cfgeneric" optional = true diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 227f231fdca..b1699f1f594 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -299,6 +299,7 @@ parameter_types! { pub const RewardAmount: Balance = 5; pub const SlashAmount: Balance = 5; pub const StalePrice: BlockNumber = 5; + pub const MaxAnswerBound: u64 = 25; } @@ -313,6 +314,7 @@ impl pallet_oracle::Config for Runtime { type RequestCost = RequestCost; type RewardAmount = RewardAmount; type SlashAmount = SlashAmount; + type MaxAnswerBound = MaxAnswerBound; } impl frame_system::offchain::CreateSignedTransaction for Runtime