Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oracle #7

Merged
merged 13 commits into from
Aug 2, 2021
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