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

Implementation of HIP-131 #858

Merged
merged 12 commits into from
Sep 4, 2024
8 changes: 4 additions & 4 deletions Cargo.lock

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

54 changes: 47 additions & 7 deletions coverage_point_calculator/src/hexes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use hex_assignments::assignment::HexAssignments;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;

use crate::{BoostedHexStatus, RadioType, Result};
use crate::{OracleBoostingStatus, RadioType, Result, SpBoostedHexStatus};

/// Breakdown of points for a hex.
///
Expand Down Expand Up @@ -58,8 +58,9 @@ pub struct CoveredHex {

pub(crate) fn clean_covered_hexes(
radio_type: RadioType,
boosted_hex_status: BoostedHexStatus,
boosted_hex_status: SpBoostedHexStatus,
ranked_coverage: Vec<RankedCoverage>,
oracle_boosting_status: OracleBoostingStatus,
) -> Result<Vec<CoveredHex>> {
// verify all hexes can obtain a base coverage point
let covered_hexes = ranked_coverage
Expand All @@ -74,9 +75,12 @@ pub(crate) fn clean_covered_hexes(
None
};

// hip-131: if the radio is banned, it automatically gets an assignment_multiplier of 0.0
// hip-103: if a hex is boosted by a service provider >=1x, the oracle
// multiplier will automatically be 1x, regardless of boosted_hex_status.
let assignment_multiplier = if ranked.boosted.is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

above comment needs an update

let assignment_multiplier = if oracle_boosting_status == OracleBoostingStatus::Banned {
dec!(0)
} else if ranked.boosted.is_some() {
dec!(1)
} else {
ranked.assignments.boosting_multiplier()
Expand Down Expand Up @@ -132,11 +136,11 @@ mod tests {
use super::*;

#[rstest]
#[case(BoostedHexStatus::Eligible)]
#[case(BoostedHexStatus::WifiLocationScoreBelowThreshold(dec!(999)))]
#[case(BoostedHexStatus::RadioThresholdNotMet)]
#[case(SpBoostedHexStatus::Eligible)]
#[case(SpBoostedHexStatus::WifiLocationScoreBelowThreshold(dec!(999)))]
#[case(SpBoostedHexStatus::RadioThresholdNotMet)]
fn hip_103_provider_boosted_hex_receives_maximum_oracle_boost(
#[case] boost_status: BoostedHexStatus,
#[case] boost_status: SpBoostedHexStatus,
) {
// Regardless of the radio's eligibility to receive provider boosted
// rewards, a boosted hex increases the oracle assignment.
Expand All @@ -162,6 +166,7 @@ mod tests {
RadioType::IndoorWifi,
boost_status,
vec![unboosted_coverage, boosted_coverage],
OracleBoostingStatus::Eligible,
)
.unwrap();

Expand All @@ -174,4 +179,39 @@ mod tests {
// provider boosted gets oracle assignment bumped to 1x
assert_eq!(dec!(1), boosted.assignment_multiplier);
}

#[rstest]
fn hip131_banned_radio() {
let unboosted_coverage = RankedCoverage {
hotspot_key: vec![1],
cbsd_id: None,
hex: hextree::Cell::from_raw(0x8c2681a3064edff).unwrap(),
rank: 1,
signal_level: SignalLevel::High,
assignments: HexAssignments {
footfall: Assignment::A,
landtype: Assignment::A,
urbanized: Assignment::A,
},
boosted: NonZeroU32::new(0),
};

let boosted_coverage = RankedCoverage {
boosted: NonZeroU32::new(5),
..unboosted_coverage.clone()
};

let covered_hexes = clean_covered_hexes(
RadioType::IndoorWifi,
SpBoostedHexStatus::Eligible,
vec![unboosted_coverage, boosted_coverage],
OracleBoostingStatus::Banned,
)
.unwrap();

dbg!(&covered_hexes);

assert_eq!(dec!(0), covered_hexes[0].assignment_multiplier);
assert_eq!(dec!(0), covered_hexes[1].assignment_multiplier);
}
}
61 changes: 46 additions & 15 deletions coverage_point_calculator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
//! - Radio must pass at least 1mb of data from 3 unique phones [HIP-84][provider-boosting]
//! - Service Provider can invalidate boosted rewards of a hotspot [HIP-125][provider-banning]
//!
//! - [OracleBoostingStatus]
//! - Eligible: Radio is eligible for normal oracle boosting multipliers
//! - Banned: Radio is banned according to hip-131 rules and all assignment_multipliers are 0.0
//!
//! [modeled-coverage]: https://github.com/helium/HIP/blob/main/0074-mobile-poc-modeled-coverage-rewards.md#outdoor-radios
//! [provider-boosting]: https://github.com/helium/HIP/blob/main/0084-service-provider-hex-boosting.md
//! [wifi-aps]: https://github.com/helium/HIP/blob/main/0093-addition-of-wifi-aps-to-mobile-subdao.md
Expand All @@ -60,6 +64,7 @@
//! [boosted-hex-restriction]: https://github.com/helium/oracles/pull/808
//! [location-gaming]: https://github.com/helium/HIP/blob/main/0119-closing-gaming-loopholes-within-the-mobile-network.md
//! [provider-banning]: https://github.com/helium/HIP/blob/main/0125-temporary-anti-gaming-measures-for-boosted-hexes.md
//! [anti-gaming]: https://github.com/helium/HIP/blob/main/0131-bridging-gap-between-verification-mappers-and-anti-gaming-measures.md
//!
pub use crate::{
hexes::{CoveredHex, HexPoints},
Expand Down Expand Up @@ -134,7 +139,7 @@ pub struct CoveragePoints {
/// Input ServiceProviderBoostedRewardEligibility
pub service_provider_boosted_reward_eligibility: SPBoostedRewardEligibility,
/// Derived Eligibility for Boosted Hex Rewards
pub boosted_hex_eligibility: BoostedHexStatus,
pub boosted_hex_eligibility: SpBoostedHexStatus,
/// Speedtests used in calculation
pub speedtests: Vec<Speedtest>,
/// Location Trust Scores used in calculation
Expand All @@ -152,18 +157,24 @@ impl CoveragePoints {
speedtests: Vec<Speedtest>,
location_trust_scores: Vec<LocationTrust>,
ranked_coverage: Vec<coverage_map::RankedCoverage>,
oracle_boosting_status: OracleBoostingStatus,
) -> Result<CoveragePoints> {
let location_trust_multiplier = location::multiplier(radio_type, &location_trust_scores);

let boost_eligibility = BoostedHexStatus::new(
let boost_eligibility = SpBoostedHexStatus::new(
radio_type,
location_trust_multiplier,
&location_trust_scores,
service_provider_boosted_reward_eligibility,
);

let covered_hexes =
hexes::clean_covered_hexes(radio_type, boost_eligibility, ranked_coverage)?;
let covered_hexes = hexes::clean_covered_hexes(
radio_type,
boost_eligibility,
ranked_coverage,
oracle_boosting_status,
)?;

let hex_coverage_points = hexes::calculated_coverage_points(&covered_hexes);

let speedtests = speedtest::clean_speedtests(speedtests);
Expand Down Expand Up @@ -220,25 +231,31 @@ impl CoveragePoints {

fn boosted_points(&self) -> Decimal {
match self.boosted_hex_eligibility {
BoostedHexStatus::Eligible => self.coverage_points.boosted,
BoostedHexStatus::WifiLocationScoreBelowThreshold(_) => dec!(0),
BoostedHexStatus::AverageAssertedDistanceOverLimit(_) => dec!(0),
BoostedHexStatus::RadioThresholdNotMet => dec!(0),
BoostedHexStatus::ServiceProviderBanned => dec!(0),
SpBoostedHexStatus::Eligible => self.coverage_points.boosted,
SpBoostedHexStatus::WifiLocationScoreBelowThreshold(_) => dec!(0),
SpBoostedHexStatus::AverageAssertedDistanceOverLimit(_) => dec!(0),
SpBoostedHexStatus::RadioThresholdNotMet => dec!(0),
SpBoostedHexStatus::ServiceProviderBanned => dec!(0),
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoostedHexStatus {
pub enum OracleBoostingStatus {
Eligible,
Banned,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpBoostedHexStatus {
Eligible,
WifiLocationScoreBelowThreshold(Decimal),
AverageAssertedDistanceOverLimit(Decimal),
RadioThresholdNotMet,
ServiceProviderBanned,
}

impl BoostedHexStatus {
impl SpBoostedHexStatus {
fn new(
radio_type: RadioType,
location_trust_multiplier: Decimal,
Expand Down Expand Up @@ -373,6 +390,7 @@ mod tests {
assignments: assignments_from(Assignment::C),
boosted: NonZeroU32::new(boost_multiplier),
}],
OracleBoostingStatus::Eligible,
)
.unwrap();

Expand All @@ -398,6 +416,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: NonZeroU32::new(5),
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi with location scores")
};
Expand Down Expand Up @@ -434,6 +453,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: NonZeroU32::new(5),
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi with location scores")
};
Expand Down Expand Up @@ -472,6 +492,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: NonZeroU32::new(5),
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi with location scores")
};
Expand Down Expand Up @@ -508,6 +529,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor cbrs with speedtests")
};
Expand Down Expand Up @@ -623,6 +645,7 @@ mod tests {
ranked_coverage(C, B, C), // 0
ranked_coverage(C, C, C), // 0
],
OracleBoostingStatus::Eligible,
)
.expect("indoor cbrs");

Expand Down Expand Up @@ -653,6 +676,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("outdoor wifi");

Expand Down Expand Up @@ -702,6 +726,7 @@ mod tests {
boosted: None,
},
],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi");

Expand All @@ -725,6 +750,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi");

Expand Down Expand Up @@ -761,6 +787,7 @@ mod tests {
speedtest_maximum(),
location_trust_maximum(),
covered_hexes.clone(),
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi");

Expand Down Expand Up @@ -792,6 +819,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("outdoor cbrs");

Expand Down Expand Up @@ -819,6 +847,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor cbrs");

Expand Down Expand Up @@ -848,6 +877,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor cbrs");

Expand Down Expand Up @@ -875,6 +905,7 @@ mod tests {
assignments: assignments_maximum(),
boosted: None,
}],
OracleBoostingStatus::Eligible,
)
.expect("indoor wifi");

Expand All @@ -889,7 +920,7 @@ mod tests {
}];

let wifi_bad_trust_score = |sp_status: SPBoostedRewardEligibility| {
BoostedHexStatus::new(
SpBoostedHexStatus::new(
RadioType::IndoorWifi,
location::multiplier(RadioType::IndoorWifi, &bad_location),
&bad_location,
Expand All @@ -899,15 +930,15 @@ mod tests {

assert_eq!(
wifi_bad_trust_score(SPBoostedRewardEligibility::Eligible),
BoostedHexStatus::WifiLocationScoreBelowThreshold(dec!(0)),
SpBoostedHexStatus::WifiLocationScoreBelowThreshold(dec!(0)),
);
assert_eq!(
wifi_bad_trust_score(SPBoostedRewardEligibility::ServiceProviderBanned),
BoostedHexStatus::ServiceProviderBanned
SpBoostedHexStatus::ServiceProviderBanned
);
assert_eq!(
wifi_bad_trust_score(SPBoostedRewardEligibility::RadioThresholdNotMet),
BoostedHexStatus::RadioThresholdNotMet
SpBoostedHexStatus::RadioThresholdNotMet
);
}

Expand Down
Loading