Skip to content
15 changes: 0 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions pallets/oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub mod pallet {
type RequestCost: Get<BalanceOf<Self>>;
type RewardAmount: Get<BalanceOf<Self>>;
type SlashAmount: Get<BalanceOf<Self>>;
type MaxAnswerBound: Get<u64>;
}

#[derive(Encode, Decode, Default, Debug, PartialEq)]
Expand Down Expand Up @@ -229,6 +230,9 @@ pub mod pallet {
UnsetController,
ControllerUsed,
SignerUsed,
AvoidPanic,
ExceedMaxAnswers,
InvalidMinAnswers
}

#[pallet::hooks]
Expand All @@ -244,12 +248,17 @@ pub mod pallet {
PrePrices::<T>::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::<T>::insert(i, set_price);
Requested::<T>::insert(i, false);
PrePrices::<T>::remove(i);
Self::handle_payout(&pre_prices, price, i);
Self::handle_payout(&slice, price, i);
}
}
0
Expand All @@ -274,6 +283,8 @@ pub mod pallet {
max_answers: u64
) -> DispatchResultWithPostInfo {
T::AddOracle::ensure_origin(origin)?;
ensure!(max_answers <= T::MaxAnswerBound::get(), Error::<T>::ExceedMaxAnswers);
ensure!(min_answers > 0, Error::<T>::InvalidMinAnswers);
let asset_info = AssetInfo {
threshold,
min_answers,
Expand Down Expand Up @@ -498,6 +509,7 @@ pub mod pallet {
.collect();
numbers.sort();
let mid = numbers.len() / 2;
// TODO maybe check length
numbers[mid]
}

Expand Down Expand Up @@ -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)
}
}
}
2 changes: 2 additions & 0 deletions pallets/oracle/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}

Expand Down Expand Up @@ -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.
Expand Down
52 changes: 48 additions & 4 deletions pallets/oracle/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Test>::ExceedMaxAnswers);

assert_noop!(Oracle::add_asset_and_info(
Origin::signed(account_2),
1,
Percent::from_percent(80),
0,
5,
), Error::<Test>::InvalidMinAnswers);
});
}

Expand Down Expand Up @@ -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(|| {
Expand Down Expand Up @@ -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),
];
Expand Down
2 changes: 1 addition & 1 deletion runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}

Expand All @@ -313,6 +314,7 @@ impl pallet_oracle::Config for Runtime {
type RequestCost = RequestCost;
type RewardAmount = RewardAmount;
type SlashAmount = SlashAmount;
type MaxAnswerBound = MaxAnswerBound;
}

impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
Expand Down