From 2d6bd0329b4882ac52ea21d7f58c64d6891f20f8 Mon Sep 17 00:00:00 2001 From: Brian Balser Date: Wed, 4 Sep 2024 16:07:39 -0400 Subject: [PATCH] Implementation of HIP-131 (#858) * Save ban_type to db when receiving new ban reports * Update query * Update coverage_point_calculator to accept hip131_ban boolean * Update mobile-verifier to pass pan flag to coverage point calculator * Update cargo lock * Update new test * Change bool to OracleBoostingStatus enum * Address feedback, move oracle_boosting_status into RadioInfo * Update Cargo.lock * use radio_info as the source for all that we can Why pass in information from a source that we're going to be using gratuitously within the same function. Did I spell that right? * Update proto back to master * Update helium-proto to tip of master --------- Co-authored-by: Michael Jeffrey --- Cargo.lock | 8 +-- coverage_point_calculator/src/hexes.rs | 54 +++++++++++++--- coverage_point_calculator/src/lib.rs | 61 ++++++++++++++----- .../tests/coverage_point_calculator.rs | 9 ++- .../migrations/36_sp_boosted_bans_type.sql | 12 ++++ mobile_verifier/src/cli/reward_from_db.rs | 2 + mobile_verifier/src/reward_shares.rs | 20 +++++- .../src/reward_shares/radio_reward_v2.rs | 10 +-- mobile_verifier/src/rewarder.rs | 20 +++++- .../src/sp_boosted_rewards_bans.rs | 54 ++++++++++++---- .../tests/integrations/boosting_oracles.rs | 2 + .../tests/integrations/modeled_coverage.rs | 7 +++ 12 files changed, 211 insertions(+), 48 deletions(-) create mode 100644 mobile_verifier/migrations/36_sp_boosted_bans_type.sql diff --git a/Cargo.lock b/Cargo.lock index cfed0a862..a06e8f3ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1617,7 +1617,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#b45858ce482f1e831d3dad07261770c7c53a1024" +source = "git+https://github.com/helium/proto?branch=master#376765fe006051d6dcccf709def58e7ed291b845" dependencies = [ "base64 0.21.7", "byteorder", @@ -1627,7 +1627,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", ] @@ -3801,7 +3801,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#b45858ce482f1e831d3dad07261770c7c53a1024" +source = "git+https://github.com/helium/proto?branch=master#376765fe006051d6dcccf709def58e7ed291b845" dependencies = [ "bytes", "prost", @@ -9851,7 +9851,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", "twox-hash", "xorf", diff --git a/coverage_point_calculator/src/hexes.rs b/coverage_point_calculator/src/hexes.rs index c784390f7..912369a85 100644 --- a/coverage_point_calculator/src/hexes.rs +++ b/coverage_point_calculator/src/hexes.rs @@ -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. /// @@ -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, + oracle_boosting_status: OracleBoostingStatus, ) -> Result> { // verify all hexes can obtain a base coverage point let covered_hexes = ranked_coverage @@ -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() { + let assignment_multiplier = if oracle_boosting_status == OracleBoostingStatus::Banned { + dec!(0) + } else if ranked.boosted.is_some() { dec!(1) } else { ranked.assignments.boosting_multiplier() @@ -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. @@ -162,6 +166,7 @@ mod tests { RadioType::IndoorWifi, boost_status, vec![unboosted_coverage, boosted_coverage], + OracleBoostingStatus::Eligible, ) .unwrap(); @@ -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); + } } diff --git a/coverage_point_calculator/src/lib.rs b/coverage_point_calculator/src/lib.rs index 6f7204e48..35f708105 100644 --- a/coverage_point_calculator/src/lib.rs +++ b/coverage_point_calculator/src/lib.rs @@ -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 @@ -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}, @@ -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, /// Location Trust Scores used in calculation @@ -152,18 +157,24 @@ impl CoveragePoints { speedtests: Vec, location_trust_scores: Vec, ranked_coverage: Vec, + oracle_boosting_status: OracleBoostingStatus, ) -> Result { 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); @@ -220,17 +231,23 @@ 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), @@ -238,7 +255,7 @@ pub enum BoostedHexStatus { ServiceProviderBanned, } -impl BoostedHexStatus { +impl SpBoostedHexStatus { fn new( radio_type: RadioType, location_trust_multiplier: Decimal, @@ -373,6 +390,7 @@ mod tests { assignments: assignments_from(Assignment::C), boosted: NonZeroU32::new(boost_multiplier), }], + OracleBoostingStatus::Eligible, ) .unwrap(); @@ -398,6 +416,7 @@ mod tests { assignments: assignments_maximum(), boosted: NonZeroU32::new(5), }], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi with location scores") }; @@ -434,6 +453,7 @@ mod tests { assignments: assignments_maximum(), boosted: NonZeroU32::new(5), }], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi with location scores") }; @@ -472,6 +492,7 @@ mod tests { assignments: assignments_maximum(), boosted: NonZeroU32::new(5), }], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi with location scores") }; @@ -508,6 +529,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("indoor cbrs with speedtests") }; @@ -623,6 +645,7 @@ mod tests { ranked_coverage(C, B, C), // 0 ranked_coverage(C, C, C), // 0 ], + OracleBoostingStatus::Eligible, ) .expect("indoor cbrs"); @@ -653,6 +676,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("outdoor wifi"); @@ -702,6 +726,7 @@ mod tests { boosted: None, }, ], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi"); @@ -725,6 +750,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi"); @@ -761,6 +787,7 @@ mod tests { speedtest_maximum(), location_trust_maximum(), covered_hexes.clone(), + OracleBoostingStatus::Eligible, ) .expect("indoor wifi"); @@ -792,6 +819,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("outdoor cbrs"); @@ -819,6 +847,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("indoor cbrs"); @@ -848,6 +877,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("indoor cbrs"); @@ -875,6 +905,7 @@ mod tests { assignments: assignments_maximum(), boosted: None, }], + OracleBoostingStatus::Eligible, ) .expect("indoor wifi"); @@ -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, @@ -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 ); } diff --git a/coverage_point_calculator/tests/coverage_point_calculator.rs b/coverage_point_calculator/tests/coverage_point_calculator.rs index f8de92fc9..b7027ac92 100644 --- a/coverage_point_calculator/tests/coverage_point_calculator.rs +++ b/coverage_point_calculator/tests/coverage_point_calculator.rs @@ -3,8 +3,8 @@ use std::num::NonZeroU32; use chrono::Utc; use coverage_map::{BoostedHexMap, RankedCoverage, SignalLevel, UnrankedCoverage}; use coverage_point_calculator::{ - BytesPs, CoveragePoints, LocationTrust, RadioType, Result, SPBoostedRewardEligibility, - Speedtest, SpeedtestTier, + BytesPs, CoveragePoints, LocationTrust, OracleBoostingStatus, RadioType, Result, + SPBoostedRewardEligibility, Speedtest, SpeedtestTier, }; use hex_assignments::{assignment::HexAssignments, Assignment}; use rust_decimal_macros::dec; @@ -56,6 +56,7 @@ fn base_radio_coverage_points() { speedtests.clone(), location_trust_scores.clone(), hexes.clone(), + OracleBoostingStatus::Eligible, ) .unwrap(); @@ -117,6 +118,7 @@ fn radios_with_coverage() { default_speedtests.clone(), default_location_trust_scores.clone(), base_hex_iter.clone().take(num_hexes).collect(), + OracleBoostingStatus::Eligible, ) .unwrap(); @@ -255,6 +257,7 @@ fn cbrs_outdoor_with_mixed_signal_level_coverage() -> Result { top_ranked_coverage(0x8c2681a30648bff, SignalLevel::Low), top_ranked_coverage(0x8c2681a30646bff, SignalLevel::Low), ], + OracleBoostingStatus::Eligible, ) .unwrap(); @@ -376,6 +379,7 @@ fn indoor_cbrs_radio( Speedtest::mock(speedtest_tier), vec![], coverage.to_owned(), + OracleBoostingStatus::Eligible, ) } @@ -389,6 +393,7 @@ fn outdoor_cbrs_radio( Speedtest::mock(speedtest_tier), vec![], coverage.to_owned(), + OracleBoostingStatus::Eligible, ) } diff --git a/mobile_verifier/migrations/36_sp_boosted_bans_type.sql b/mobile_verifier/migrations/36_sp_boosted_bans_type.sql new file mode 100644 index 000000000..95fe3e235 --- /dev/null +++ b/mobile_verifier/migrations/36_sp_boosted_bans_type.sql @@ -0,0 +1,12 @@ +ALTER TABLE sp_boosted_rewards_bans ADD COLUMN ban_type TEXT; + +UPDATE sp_boosted_rewards_bans SET ban_type = 'boosted_hex'; + +ALTER TABLE sp_boosted_rewards_bans ALTER COLUMN ban_type SET NOT NULL; + +ALTER TABLE sp_boosted_rewards_bans DROP CONSTRAINT sp_boosted_rewards_bans_pkey; + +ALTER TABLE sp_boosted_rewards_bans ADD PRIMARY KEY (ban_type, radio_type, radio_key, received_timestamp); + + + diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index 7de6ce945..d0f9dfa60 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -4,6 +4,7 @@ use crate::{ get_scheduled_tokens_for_poc, CoverageShares, DataTransferAndPocAllocatedRewardBuckets, }, rewarder::boosted_hex_eligibility::BoostedHexEligibility, + sp_boosted_rewards_bans::BannedRadios, speedtests_average::SpeedtestAverages, Settings, }; @@ -48,6 +49,7 @@ impl Cmd { &speedtest_averages, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await?; diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 20a660432..e5f2d2d00 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -4,12 +4,13 @@ use crate::{ heartbeats::HeartbeatReward, rewarder::boosted_hex_eligibility::BoostedHexEligibility, seniority::Seniority, + sp_boosted_rewards_bans::BannedRadios, speedtests_average::SpeedtestAverages, subscriber_location::SubscriberValidatedLocations, subscriber_verified_mapping_event::VerifiedSubscriberVerifiedMappingEventShares, }; use chrono::{DateTime, Duration, Utc}; -use coverage_point_calculator::SPBoostedRewardEligibility; +use coverage_point_calculator::{OracleBoostingStatus, SPBoostedRewardEligibility}; use file_store::traits::TimestampEncode; use futures::{Stream, StreamExt}; use helium_crypto::PublicKeyBinary; @@ -521,6 +522,7 @@ struct RadioInfo { trust_scores: Vec, sp_boosted_reward_eligibility: SPBoostedRewardEligibility, speedtests: Vec, + oracle_boosting_status: OracleBoostingStatus, } #[derive(Debug)] @@ -536,6 +538,7 @@ impl CoverageShares { speedtest_averages: &SpeedtestAverages, boosted_hexes: &BoostedHexes, boosted_hex_eligibility: &BoostedHexEligibility, + banned_radios: &BannedRadios, reward_period: &Range>, ) -> anyhow::Result { let mut radio_infos: HashMap = HashMap::new(); @@ -606,6 +609,12 @@ impl CoverageShares { }) .collect(); + let oracle_boosting_status = if banned_radios.contains(&pubkey, cbsd_id.as_deref()) { + OracleBoostingStatus::Banned + } else { + OracleBoostingStatus::Eligible + }; + let sp_boosted_reward_eligibility = boosted_hex_eligibility.eligibility(pubkey, cbsd_id); @@ -627,6 +636,7 @@ impl CoverageShares { trust_scores, sp_boosted_reward_eligibility, speedtests, + oracle_boosting_status, }, ); } @@ -660,6 +670,7 @@ impl CoverageShares { radio_info.speedtests.clone(), radio_info.trust_scores.clone(), hexes, + radio_info.oracle_boosting_status, )?; Ok(coverage_points) @@ -1306,6 +1317,7 @@ mod test { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await @@ -1708,6 +1720,7 @@ mod test { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await @@ -1888,6 +1901,7 @@ mod test { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await @@ -2021,6 +2035,7 @@ mod test { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await @@ -2155,6 +2170,7 @@ mod test { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await @@ -2269,6 +2285,7 @@ mod test { timestamp: now, }, ], + oracle_boosting_status: OracleBoostingStatus::Eligible, }, ); radio_infos.insert( @@ -2289,6 +2306,7 @@ mod test { }, sp_boosted_reward_eligibility: SPBoostedRewardEligibility::Eligible, speedtests: vec![], + oracle_boosting_status: OracleBoostingStatus::Eligible, }, ); diff --git a/mobile_verifier/src/reward_shares/radio_reward_v2.rs b/mobile_verifier/src/reward_shares/radio_reward_v2.rs index bb7344f0a..629e3ce13 100644 --- a/mobile_verifier/src/reward_shares/radio_reward_v2.rs +++ b/mobile_verifier/src/reward_shares/radio_reward_v2.rs @@ -59,17 +59,17 @@ impl RadioRewardV2Ext for coverage_point_calculator::CoveragePoints { fn proto_boosted_hex_status(&self) -> BoostedHexStatus { match self.boosted_hex_eligibility { - coverage_point_calculator::BoostedHexStatus::Eligible => BoostedHexStatus::Eligible, - coverage_point_calculator::BoostedHexStatus::WifiLocationScoreBelowThreshold(_) => { + coverage_point_calculator::SpBoostedHexStatus::Eligible => BoostedHexStatus::Eligible, + coverage_point_calculator::SpBoostedHexStatus::WifiLocationScoreBelowThreshold(_) => { BoostedHexStatus::LocationScoreBelowThreshold } - coverage_point_calculator::BoostedHexStatus::RadioThresholdNotMet => { + coverage_point_calculator::SpBoostedHexStatus::RadioThresholdNotMet => { BoostedHexStatus::RadioThresholdNotMet } - coverage_point_calculator::BoostedHexStatus::ServiceProviderBanned => { + coverage_point_calculator::SpBoostedHexStatus::ServiceProviderBanned => { BoostedHexStatus::ServiceProviderBan } - coverage_point_calculator::BoostedHexStatus::AverageAssertedDistanceOverLimit(_) => { + coverage_point_calculator::SpBoostedHexStatus::AverageAssertedDistanceOverLimit(_) => { BoostedHexStatus::AverageAssertedDistanceOverLimit } } diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 2befe03ac..76cb12313 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -24,8 +24,9 @@ use futures_util::TryFutureExt; use helium_proto::{ reward_manifest::RewardData::MobileRewardData, services::poc_mobile::{ - self as proto, mobile_reward_share::Reward as ProtoReward, MobileRewardShare, - UnallocatedReward, UnallocatedRewardType, + self as proto, mobile_reward_share::Reward as ProtoReward, + service_provider_boosted_rewards_banned_radio_req_v1::SpBoostedRewardsBannedRadioBanType, + MobileRewardShare, UnallocatedReward, UnallocatedRewardType, }, MobileRewardData as ManifestMobileRewardData, RewardManifest, }; @@ -427,15 +428,28 @@ async fn reward_poc( let boosted_hex_eligibility = BoostedHexEligibility::new( radio_threshold::verified_radio_thresholds(pool, reward_period).await?, - sp_boosted_rewards_bans::db::get_banned_radios(pool, reward_period.end).await?, + sp_boosted_rewards_bans::db::get_banned_radios( + pool, + SpBoostedRewardsBannedRadioBanType::BoostedHex, + reward_period.end, + ) + .await?, ); + let poc_banned_radios = sp_boosted_rewards_bans::db::get_banned_radios( + pool, + SpBoostedRewardsBannedRadioBanType::Poc, + reward_period.end, + ) + .await?; + let coverage_shares = CoverageShares::new( pool, heartbeats, &speedtest_averages, &boosted_hexes, &boosted_hex_eligibility, + &poc_banned_radios, reward_period, ) .await?; diff --git a/mobile_verifier/src/sp_boosted_rewards_bans.rs b/mobile_verifier/src/sp_boosted_rewards_bans.rs index c4bafc051..597de524f 100644 --- a/mobile_verifier/src/sp_boosted_rewards_bans.rs +++ b/mobile_verifier/src/sp_boosted_rewards_bans.rs @@ -16,7 +16,8 @@ use helium_proto::services::{ mobile_config::NetworkKeyRole, poc_mobile::{ service_provider_boosted_rewards_banned_radio_req_v1::{ - KeyType as ProtoKeyType, SpBoostedRewardsBannedRadioReason, + KeyType as ProtoKeyType, SpBoostedRewardsBannedRadioBanType, + SpBoostedRewardsBannedRadioReason, }, SeniorityUpdate as SeniorityUpdateProto, SeniorityUpdateReason, ServiceProviderBoostedRewardsBannedRadioIngestReportV1, @@ -43,6 +44,7 @@ struct BannedRadioReport { key: OwnedKeyType, until: DateTime, reason: SpBoostedRewardsBannedRadioReason, + ban_type: SpBoostedRewardsBannedRadioBanType, } impl BannedRadioReport { @@ -65,6 +67,7 @@ impl TryFrom for BannedR .ok_or_else(|| anyhow::anyhow!("invalid ingest report"))?; let reason = report.reason(); + let ban_type = report.ban_type(); let key = match report.key_type { Some(ProtoKeyType::CbsdId(cbsd_id)) => OwnedKeyType::Cbrs(cbsd_id), @@ -88,6 +91,7 @@ impl TryFrom for BannedR .single() .ok_or_else(|| anyhow::anyhow!("invalid until: {}", report.until))?, reason, + ban_type, }) } } @@ -316,17 +320,20 @@ pub mod db { pub async fn get_banned_radios( pool: &PgPool, + ban_type: SpBoostedRewardsBannedRadioBanType, date_time: DateTime, ) -> anyhow::Result { sqlx::query( r#" SELECT distinct radio_type, radio_key FROM sp_boosted_rewards_bans - WHERE received_timestamp <= $1 - AND until > $1 - AND COALESCE(invalidated_at > $1, TRUE) + WHERE ban_type = $1 + AND received_timestamp <= $2 + AND until > $2 + AND COALESCE(invalidated_at > $2, TRUE) "#, ) + .bind(ban_type.as_str_name()) .bind(date_time) .fetch(pool) .map_err(anyhow::Error::from) @@ -381,10 +388,11 @@ pub mod db { ) -> anyhow::Result<()> { sqlx::query( r#" - INSERT INTO sp_boosted_rewards_bans(radio_type, radio_key, received_timestamp, until) - VALUES($1,$2,$3,$4) + INSERT INTO sp_boosted_rewards_bans(ban_type, radio_type, radio_key, received_timestamp, until) + VALUES($1,$2,$3,$4,$5) "#, ) + .bind(report.ban_type.as_str_name()) .bind(report.radio_type()) .bind(&report.key) .bind(report.received_timestamp) @@ -405,11 +413,13 @@ pub mod db { SET invalidated_at = now() WHERE radio_type = $1 AND radio_key = $2 - AND received_timestamp <= $3 + AND ban_type = $3 + AND received_timestamp <= $4 "#, ) .bind(report.radio_type()) .bind(&report.key) + .bind(report.ban_type.as_str_name()) .bind(report.received_timestamp) .execute(transaction) .await @@ -497,6 +507,7 @@ mod tests { until: until.timestamp() as u64, signature: vec![], key_type: Some(ProtoKeyType::HotspotKey(key.into())), + ban_type: SpBoostedRewardsBannedRadioBanType::BoostedHex as i32, }), } } @@ -516,6 +527,7 @@ mod tests { until: until.timestamp() as u64, signature: vec![], key_type: Some(ProtoKeyType::CbsdId(cbsd_id)), + ban_type: SpBoostedRewardsBannedRadioBanType::BoostedHex as i32, }), } } @@ -539,7 +551,12 @@ mod tests { .await?; transaction.commit().await?; - let banned_radios = db::get_banned_radios(&pool, Utc::now()).await?; + let banned_radios = db::get_banned_radios( + &pool, + SpBoostedRewardsBannedRadioBanType::BoostedHex, + Utc::now(), + ) + .await?; let result = banned_radios.contains(&keypair.public_key().to_owned().into(), Some(&cbsd_id)); @@ -558,7 +575,12 @@ mod tests { .await?; transaction.commit().await?; - let banned_radios = db::get_banned_radios(&pool, Utc::now()).await?; + let banned_radios = db::get_banned_radios( + &pool, + SpBoostedRewardsBannedRadioBanType::BoostedHex, + Utc::now(), + ) + .await?; let result = banned_radios.contains(&keypair.public_key().to_owned().into(), Some(&cbsd_id)); @@ -585,7 +607,12 @@ mod tests { .await?; transaction.commit().await?; - let banned_radios = db::get_banned_radios(&pool, Utc::now()).await?; + let banned_radios = db::get_banned_radios( + &pool, + SpBoostedRewardsBannedRadioBanType::BoostedHex, + Utc::now(), + ) + .await?; let result = banned_radios.contains(&keypair.public_key().to_owned().into(), None); assert!(result); @@ -603,7 +630,12 @@ mod tests { .await?; transaction.commit().await?; - let banned_radios = db::get_banned_radios(&pool, Utc::now()).await?; + let banned_radios = db::get_banned_radios( + &pool, + SpBoostedRewardsBannedRadioBanType::BoostedHex, + Utc::now(), + ) + .await?; let result = banned_radios.contains(&keypair.public_key().to_owned().into(), None); assert!(!result); diff --git a/mobile_verifier/tests/integrations/boosting_oracles.rs b/mobile_verifier/tests/integrations/boosting_oracles.rs index d5d00d844..f9f03e351 100644 --- a/mobile_verifier/tests/integrations/boosting_oracles.rs +++ b/mobile_verifier/tests/integrations/boosting_oracles.rs @@ -21,6 +21,7 @@ use mobile_verifier::{ reward_shares::CoverageShares, rewarder::boosted_hex_eligibility::BoostedHexEligibility, seniority::{Seniority, SeniorityUpdate}, + sp_boosted_rewards_bans::BannedRadios, speedtests::Speedtest, speedtests_average::{SpeedtestAverage, SpeedtestAverages}, GatewayResolution, GatewayResolver, @@ -402,6 +403,7 @@ async fn test_footfall_and_urbanization_and_landtype(pool: PgPool) -> anyhow::Re &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &epoch, ) .await diff --git a/mobile_verifier/tests/integrations/modeled_coverage.rs b/mobile_verifier/tests/integrations/modeled_coverage.rs index b9f20f800..bb9c406f9 100644 --- a/mobile_verifier/tests/integrations/modeled_coverage.rs +++ b/mobile_verifier/tests/integrations/modeled_coverage.rs @@ -24,6 +24,7 @@ use mobile_verifier::{ reward_shares::CoverageShares, rewarder::boosted_hex_eligibility::BoostedHexEligibility, seniority::{Seniority, SeniorityUpdate}, + sp_boosted_rewards_bans::BannedRadios, speedtests::Speedtest, speedtests_average::{SpeedtestAverage, SpeedtestAverages}, GatewayResolution, GatewayResolver, IsAuthorized, @@ -497,6 +498,7 @@ async fn scenario_one(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?; @@ -599,6 +601,7 @@ async fn scenario_two(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?; @@ -887,6 +890,7 @@ async fn scenario_three(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &boosted_hexes, &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?; @@ -976,6 +980,7 @@ async fn scenario_four(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?; @@ -1077,6 +1082,7 @@ async fn scenario_five(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?; @@ -1326,6 +1332,7 @@ async fn scenario_six(pool: PgPool) -> anyhow::Result<()> { &speedtest_avgs, &BoostedHexes::default(), &BoostedHexEligibility::default(), + &BannedRadios::default(), &reward_period, ) .await?;