From b3585cd54380341786c633fe9cb48bb96da4b7c0 Mon Sep 17 00:00:00 2001 From: Anatolii Kurotych Date: Thu, 30 May 2024 16:11:57 +0300 Subject: [PATCH] Create hex_assignments crate (#817) * Create hex_assignments * Fix fmt * Add HexBoostDataAssignments trait * Remove HexAssignments::test_best * Remove new_mock use optional parameter in new * Format Cargo.toml --- Cargo.lock | 16 + Cargo.toml | 1 + hex_assignments/Cargo.toml | 18 ++ .../src}/assignment.rs | 11 - .../src}/footfall.rs | 40 +-- .../src}/landtype.rs | 40 +-- hex_assignments/src/lib.rs | 274 +++++++++++++++++ hex_assignments/src/urbanization.rs | 40 +++ mobile_verifier/Cargo.toml | 1 + .../src/boosting_oracles/data_sets.rs | 85 +++++- mobile_verifier/src/boosting_oracles/mod.rs | 281 ------------------ .../src/boosting_oracles/urbanization.rs | 68 ----- mobile_verifier/src/cli/verify_disktree.rs | 7 +- mobile_verifier/src/coverage.rs | 31 +- mobile_verifier/src/reward_shares.rs | 15 +- .../tests/integrations/boosting_oracles.rs | 7 +- .../tests/integrations/common/mod.rs | 6 +- 17 files changed, 480 insertions(+), 461 deletions(-) create mode 100644 hex_assignments/Cargo.toml rename {mobile_verifier/src/boosting_oracles => hex_assignments/src}/assignment.rs (95%) rename {mobile_verifier/src/boosting_oracles => hex_assignments/src}/footfall.rs (53%) rename {mobile_verifier/src/boosting_oracles => hex_assignments/src}/landtype.rs (79%) create mode 100644 hex_assignments/src/lib.rs create mode 100644 hex_assignments/src/urbanization.rs delete mode 100644 mobile_verifier/src/boosting_oracles/urbanization.rs diff --git a/Cargo.lock b/Cargo.lock index 35c5bea7c..43726fc94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3495,6 +3495,21 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-assignments" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "derive_builder", + "helium-proto", + "hextree", + "rust_decimal", + "rust_decimal_macros", + "sqlx", +] + [[package]] name = "hex-literal" version = "0.3.4" @@ -4712,6 +4727,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-proto", + "hex-assignments", "hextree", "http-serde", "humantime", diff --git a/Cargo.toml b/Cargo.toml index 47649d3ef..a858438fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ members = [ "reward_scheduler", "solana", "task_manager", + "hex_assignments" ] resolver = "2" diff --git a/hex_assignments/Cargo.toml b/hex_assignments/Cargo.toml new file mode 100644 index 000000000..a37e15b67 --- /dev/null +++ b/hex_assignments/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "hex-assignments" +version = "0.1.0" +description = "Hex Assignments" +edition.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +anyhow = { workspace = true } +hextree = { workspace = true } +sqlx = { version = "*", features = ["runtime-tokio-rustls"] } +rust_decimal = { workspace = true } +rust_decimal_macros = { workspace = true } +helium-proto = { workspace = true } +async-trait = { workspace = true } +chrono = { workspace = true } +derive_builder = { workspace = true } diff --git a/mobile_verifier/src/boosting_oracles/assignment.rs b/hex_assignments/src/assignment.rs similarity index 95% rename from mobile_verifier/src/boosting_oracles/assignment.rs rename to hex_assignments/src/assignment.rs index 8d8a37321..90a99d990 100644 --- a/mobile_verifier/src/boosting_oracles/assignment.rs +++ b/hex_assignments/src/assignment.rs @@ -149,14 +149,3 @@ impl HexAssignmentsBuilder { }) } } - -#[cfg(test)] -impl HexAssignments { - pub fn test_best() -> Self { - Self { - footfall: Assignment::A, - urbanized: Assignment::A, - landtype: Assignment::A, - } - } -} diff --git a/mobile_verifier/src/boosting_oracles/footfall.rs b/hex_assignments/src/footfall.rs similarity index 53% rename from mobile_verifier/src/boosting_oracles/footfall.rs rename to hex_assignments/src/footfall.rs index 4af2ebaf5..be092800e 100644 --- a/mobile_verifier/src/boosting_oracles/footfall.rs +++ b/hex_assignments/src/footfall.rs @@ -1,26 +1,17 @@ -use std::path::Path; - use chrono::{DateTime, Utc}; use hextree::disktree::DiskTreeMap; -use super::{Assignment, DataSet, DataSetType, HexAssignment}; +use super::{Assignment, HexAssignment}; pub struct Footfall { - footfall: Option, - timestamp: Option>, + pub footfall: Option, + pub timestamp: Option>, } impl Footfall { - pub fn new() -> Self { + pub fn new(footfall: Option) -> Self { Self { - footfall: None, - timestamp: None, - } - } - - pub fn new_mock(footfall: DiskTreeMap) -> Self { - Self { - footfall: Some(footfall), + footfall, timestamp: None, } } @@ -28,26 +19,7 @@ impl Footfall { impl Default for Footfall { fn default() -> Self { - Self::new() - } -} - -#[async_trait::async_trait] -impl DataSet for Footfall { - const TYPE: DataSetType = DataSetType::Footfall; - - fn timestamp(&self) -> Option> { - self.timestamp - } - - fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { - self.footfall = Some(DiskTreeMap::open(path)?); - self.timestamp = Some(time_to_use); - Ok(()) - } - - fn is_ready(&self) -> bool { - self.footfall.is_some() + Self::new(None) } } diff --git a/mobile_verifier/src/boosting_oracles/landtype.rs b/hex_assignments/src/landtype.rs similarity index 79% rename from mobile_verifier/src/boosting_oracles/landtype.rs rename to hex_assignments/src/landtype.rs index b6cda7aef..29ba9b645 100644 --- a/mobile_verifier/src/boosting_oracles/landtype.rs +++ b/hex_assignments/src/landtype.rs @@ -1,26 +1,17 @@ -use std::path::Path; - use chrono::{DateTime, Utc}; use hextree::disktree::DiskTreeMap; -use super::{Assignment, DataSet, DataSetType, HexAssignment}; +use super::{Assignment, HexAssignment}; pub struct Landtype { - landtype: Option, - timestamp: Option>, + pub landtype: Option, + pub timestamp: Option>, } impl Landtype { - pub fn new() -> Self { + pub fn new(landtype: Option) -> Self { Self { - landtype: None, - timestamp: None, - } - } - - pub fn new_mock(landtype: DiskTreeMap) -> Self { - Self { - landtype: Some(landtype), + landtype, timestamp: None, } } @@ -28,26 +19,7 @@ impl Landtype { impl Default for Landtype { fn default() -> Self { - Self::new() - } -} - -#[async_trait::async_trait] -impl DataSet for Landtype { - const TYPE: DataSetType = DataSetType::Landtype; - - fn timestamp(&self) -> Option> { - self.timestamp - } - - fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { - self.landtype = Some(DiskTreeMap::open(path)?); - self.timestamp = Some(time_to_use); - Ok(()) - } - - fn is_ready(&self) -> bool { - self.landtype.is_some() + Self::new(None) } } diff --git a/hex_assignments/src/lib.rs b/hex_assignments/src/lib.rs new file mode 100644 index 000000000..da87d9e5d --- /dev/null +++ b/hex_assignments/src/lib.rs @@ -0,0 +1,274 @@ +pub mod assignment; +pub mod footfall; +pub mod landtype; +pub mod urbanization; + +use std::collections::HashMap; + +pub use assignment::Assignment; +use assignment::HexAssignments; + +pub trait HexAssignment: Send + Sync + 'static { + fn assignment(&self, cell: hextree::Cell) -> anyhow::Result; +} + +impl HexAssignment for HashMap { + fn assignment(&self, cell: hextree::Cell) -> anyhow::Result { + Ok(*self.get(&cell).unwrap()) + } +} + +impl HexAssignment for Assignment { + fn assignment(&self, _cell: hextree::Cell) -> anyhow::Result { + Ok(*self) + } +} + +pub trait HexBoostDataAssignments: Send + Sync + 'static { + fn assignments(&self, cell: hextree::Cell) -> anyhow::Result; +} + +#[derive(derive_builder::Builder)] +#[builder(pattern = "owned")] +pub struct HexBoostData { + pub footfall: Foot, + pub landtype: Land, + pub urbanization: Urban, +} +impl HexBoostData { + pub fn builder() -> HexBoostDataBuilder { + HexBoostDataBuilder::default() + } +} + +impl HexBoostDataAssignments for HexBoostData +where + Foot: HexAssignment, + Land: HexAssignment, + Urban: HexAssignment, +{ + fn assignments(&self, cell: hextree::Cell) -> anyhow::Result { + HexAssignments::builder(cell) + .footfall(&self.footfall) + .landtype(&self.landtype) + .urbanized(&self.urbanization) + .build() + } +} + +#[cfg(test)] +mod tests { + + use std::io::Cursor; + + use hextree::{disktree::DiskTreeMap, HexTreeMap}; + + use self::{footfall::Footfall, landtype::Landtype, urbanization::Urbanization}; + + use super::*; + + #[test] + fn test_hex_boost_data() -> anyhow::Result<()> { + // This test will break if any of the logic deriving Assignments from + // the underlying DiskTreeMap's changes. + + let unknown_cell = hextree::Cell::from_raw(0x8c2681a3064d9ff)?; + + // Types of Cells + // yellow - POI ≥ 1 Urbanized + let poi_built_urbanized = hextree::Cell::from_raw(0x8c2681a3064dbff)?; + let poi_grass_urbanized = hextree::Cell::from_raw(0x8c2681a3064ddff)?; + let poi_water_urbanized = hextree::Cell::from_raw(0x8c2681a3064e1ff)?; + // orange - POI ≥ 1 Not Urbanized + let poi_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e3ff)?; + let poi_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e5ff)?; + let poi_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e7ff)?; + // light green - Point of Interest Urbanized + let poi_no_data_built_urbanized = hextree::Cell::from_raw(0x8c2681a3064e9ff)?; + let poi_no_data_grass_urbanized = hextree::Cell::from_raw(0x8c2681a3064ebff)?; + let poi_no_data_water_urbanized = hextree::Cell::from_raw(0x8c2681a3064edff)?; + // dark green - Point of Interest Not Urbanized + let poi_no_data_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a306501ff)?; + let poi_no_data_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a306503ff)?; + let poi_no_data_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a306505ff)?; + // light blue - No POI Urbanized + let no_poi_built_urbanized = hextree::Cell::from_raw(0x8c2681a306507ff)?; + let no_poi_grass_urbanized = hextree::Cell::from_raw(0x8c2681a306509ff)?; + let no_poi_water_urbanized = hextree::Cell::from_raw(0x8c2681a30650bff)?; + // dark blue - No POI Not Urbanized + let no_poi_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a30650dff)?; + let no_poi_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a306511ff)?; + let no_poi_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a306513ff)?; + // gray - Outside of USA + let poi_built_outside_us = hextree::Cell::from_raw(0x8c2681a306515ff)?; + let poi_grass_outside_us = hextree::Cell::from_raw(0x8c2681a306517ff)?; + let poi_water_outside_us = hextree::Cell::from_raw(0x8c2681a306519ff)?; + let poi_no_data_built_outside_us = hextree::Cell::from_raw(0x8c2681a30651bff)?; + let poi_no_data_grass_outside_us = hextree::Cell::from_raw(0x8c2681a30651dff)?; + let poi_no_data_water_outside_us = hextree::Cell::from_raw(0x8c2681a306521ff)?; + let no_poi_built_outside_us = hextree::Cell::from_raw(0x8c2681a306523ff)?; + let no_poi_grass_outside_us = hextree::Cell::from_raw(0x8c2681a306525ff)?; + let no_poi_water_outside_us = hextree::Cell::from_raw(0x8c2681a306527ff)?; + + // Footfall Data + // POI - footfalls > 1 for a POI across hexes + // POI No Data - No footfalls for a POI across any hexes + // NO POI - Does not exist + let mut footfall = HexTreeMap::::new(); + footfall.insert(poi_built_urbanized, 42); + footfall.insert(poi_grass_urbanized, 42); + footfall.insert(poi_water_urbanized, 42); + footfall.insert(poi_built_not_urbanized, 42); + footfall.insert(poi_grass_not_urbanized, 42); + footfall.insert(poi_water_not_urbanized, 42); + footfall.insert(poi_no_data_built_urbanized, 0); + footfall.insert(poi_no_data_grass_urbanized, 0); + footfall.insert(poi_no_data_water_urbanized, 0); + footfall.insert(poi_no_data_built_not_urbanized, 0); + footfall.insert(poi_no_data_grass_not_urbanized, 0); + footfall.insert(poi_no_data_water_not_urbanized, 0); + footfall.insert(poi_built_outside_us, 42); + footfall.insert(poi_grass_outside_us, 42); + footfall.insert(poi_water_outside_us, 42); + footfall.insert(poi_no_data_built_outside_us, 0); + footfall.insert(poi_no_data_grass_outside_us, 0); + footfall.insert(poi_no_data_water_outside_us, 0); + + // Landtype Data + // Map to enum values for Landtype + // An unknown cell is considered Assignment::C + let mut landtype = HexTreeMap::::new(); + landtype.insert(poi_built_urbanized, 50); + landtype.insert(poi_grass_urbanized, 30); + landtype.insert(poi_water_urbanized, 80); + landtype.insert(poi_built_not_urbanized, 50); + landtype.insert(poi_grass_not_urbanized, 30); + landtype.insert(poi_water_not_urbanized, 80); + landtype.insert(poi_no_data_built_urbanized, 50); + landtype.insert(poi_no_data_grass_urbanized, 30); + landtype.insert(poi_no_data_water_urbanized, 80); + landtype.insert(poi_no_data_built_not_urbanized, 50); + landtype.insert(poi_no_data_grass_not_urbanized, 30); + landtype.insert(poi_no_data_water_not_urbanized, 80); + landtype.insert(no_poi_built_urbanized, 50); + landtype.insert(no_poi_grass_urbanized, 30); + landtype.insert(no_poi_water_urbanized, 80); + landtype.insert(no_poi_built_not_urbanized, 50); + landtype.insert(no_poi_grass_not_urbanized, 30); + landtype.insert(no_poi_water_not_urbanized, 80); + landtype.insert(poi_built_outside_us, 50); + landtype.insert(poi_grass_outside_us, 30); + landtype.insert(poi_water_outside_us, 80); + landtype.insert(poi_no_data_built_outside_us, 50); + landtype.insert(poi_no_data_grass_outside_us, 30); + landtype.insert(poi_no_data_water_outside_us, 80); + landtype.insert(no_poi_built_outside_us, 50); + landtype.insert(no_poi_grass_outside_us, 30); + landtype.insert(no_poi_water_outside_us, 80); + + // Urbanized data + // Urban - something in the map, and in the geofence + // Not Urban - nothing in the map, but in the geofence + // Outside - not in the geofence, urbanized hex never considered + let mut urbanized = HexTreeMap::::new(); + urbanized.insert(poi_built_urbanized, 1); + urbanized.insert(poi_grass_urbanized, 1); + urbanized.insert(poi_water_urbanized, 1); + urbanized.insert(poi_no_data_built_urbanized, 1); + urbanized.insert(poi_no_data_grass_urbanized, 1); + urbanized.insert(poi_no_data_water_urbanized, 1); + urbanized.insert(no_poi_built_urbanized, 1); + urbanized.insert(no_poi_grass_urbanized, 1); + urbanized.insert(no_poi_water_urbanized, 1); + + let inside_usa = [ + poi_built_urbanized, + poi_grass_urbanized, + poi_water_urbanized, + poi_built_not_urbanized, + poi_grass_not_urbanized, + poi_water_not_urbanized, + poi_no_data_built_urbanized, + poi_no_data_grass_urbanized, + poi_no_data_water_urbanized, + poi_no_data_built_not_urbanized, + poi_no_data_grass_not_urbanized, + poi_no_data_water_not_urbanized, + no_poi_built_urbanized, + no_poi_grass_urbanized, + no_poi_water_urbanized, + no_poi_built_not_urbanized, + no_poi_grass_not_urbanized, + no_poi_water_not_urbanized, + ]; + for inside_usa in inside_usa.into_iter() { + urbanized.entry(inside_usa).or_insert(0); + } + // These vectors are a standin for the file system + let mut urbanized_buf = vec![]; + let mut footfall_buff = vec![]; + let mut landtype_buf = vec![]; + + // Turn the HexTrees into DiskTrees + urbanized.to_disktree(Cursor::new(&mut urbanized_buf), |w, v| w.write_all(&[*v]))?; + footfall.to_disktree(Cursor::new(&mut footfall_buff), |w, v| w.write_all(&[*v]))?; + landtype.to_disktree(Cursor::new(&mut landtype_buf), |w, v| w.write_all(&[*v]))?; + + let footfall = Footfall::new(Some(DiskTreeMap::with_buf(footfall_buff)?)); + let landtype = Landtype::new(Some(DiskTreeMap::with_buf(landtype_buf)?)); + let urbanization = Urbanization::new(Some(DiskTreeMap::with_buf(urbanized_buf)?)); + + // Let the testing commence + let data = HexBoostData::builder() + .footfall(footfall) + .landtype(landtype) + .urbanization(urbanization) + .build()?; + + // NOTE(mj): formatting ignored to make it easier to see the expected change in assignments. + // NOTE(mj): The semicolon at the end of the block is there to keep rust from + // complaining about attributes on expression being experimental. + #[rustfmt::skip] + { + use Assignment::*; + // yellow + assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: A }, data.assignments(poi_built_urbanized)?); + assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: A }, data.assignments(poi_grass_urbanized)?); + assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: A }, data.assignments(poi_water_urbanized)?); + // orange + assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: B }, data.assignments(poi_built_not_urbanized)?); + assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: B }, data.assignments(poi_grass_not_urbanized)?); + assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: B }, data.assignments(poi_water_not_urbanized)?); + // light green + assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: A }, data.assignments(poi_no_data_built_urbanized)?); + assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: A }, data.assignments(poi_no_data_grass_urbanized)?); + assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: A }, data.assignments(poi_no_data_water_urbanized)?); + // green + assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: B }, data.assignments(poi_no_data_built_not_urbanized)?); + assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: B }, data.assignments(poi_no_data_grass_not_urbanized)?); + assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: B }, data.assignments(poi_no_data_water_not_urbanized)?); + // light blue + assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: A }, data.assignments(no_poi_built_urbanized)?); + assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: A }, data.assignments(no_poi_grass_urbanized)?); + assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: A }, data.assignments(no_poi_water_urbanized)?); + // dark blue + assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: B }, data.assignments(no_poi_built_not_urbanized)?); + assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: B }, data.assignments(no_poi_grass_not_urbanized)?); + assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: B }, data.assignments(no_poi_water_not_urbanized)?); + // gray + assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: C }, data.assignments(poi_built_outside_us)?); + assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: C }, data.assignments(poi_grass_outside_us)?); + assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: C }, data.assignments(poi_water_outside_us)?); + assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: C }, data.assignments(poi_no_data_built_outside_us)?); + assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: C }, data.assignments(poi_no_data_grass_outside_us)?); + assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: C }, data.assignments(poi_no_data_water_outside_us)?); + assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: C }, data.assignments(no_poi_built_outside_us)?); + assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: C }, data.assignments(no_poi_grass_outside_us)?); + assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: C }, data.assignments(no_poi_water_outside_us)?); + // never inserted + assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: C }, data.assignments(unknown_cell)?); + }; + + Ok(()) + } +} diff --git a/hex_assignments/src/urbanization.rs b/hex_assignments/src/urbanization.rs new file mode 100644 index 000000000..2cc2ca79f --- /dev/null +++ b/hex_assignments/src/urbanization.rs @@ -0,0 +1,40 @@ +use chrono::{DateTime, Utc}; +use hextree::disktree::DiskTreeMap; + +use super::{Assignment, HexAssignment}; + +pub struct Urbanization { + pub urbanized: Option, + pub timestamp: Option>, +} + +impl Urbanization { + pub fn new(urbanized: Option) -> Self { + Self { + urbanized, + timestamp: None, + } + } +} + +impl Default for Urbanization { + fn default() -> Self { + Self::new(None) + } +} + +impl HexAssignment for Urbanization { + fn assignment(&self, cell: hextree::Cell) -> anyhow::Result { + let Some(ref urbanized) = self.urbanized else { + anyhow::bail!("No urbanization data set has been loaded"); + }; + match urbanized.get(cell)? { + Some((_, &[1])) => Ok(Assignment::A), + Some((_, &[0])) => Ok(Assignment::B), + None => Ok(Assignment::C), + Some((_, other)) => { + anyhow::bail!("unexpected urbanization disktree data: {cell:?} {other:?}") + } + } + } +} diff --git a/mobile_verifier/Cargo.toml b/mobile_verifier/Cargo.toml index 044256d9d..75d86b1ec 100644 --- a/mobile_verifier/Cargo.toml +++ b/mobile_verifier/Cargo.toml @@ -57,6 +57,7 @@ derive_builder = { workspace = true } regex = "1" humantime-serde = { workspace = true } custom-tracing = { path = "../custom_tracing" } +hex-assignments = { path = "../hex_assignments" } [dev-dependencies] backon = "0" diff --git a/mobile_verifier/src/boosting_oracles/data_sets.rs b/mobile_verifier/src/boosting_oracles/data_sets.rs index 76eaec1a4..e0065e055 100644 --- a/mobile_verifier/src/boosting_oracles/data_sets.rs +++ b/mobile_verifier/src/boosting_oracles/data_sets.rs @@ -14,6 +14,7 @@ use file_store::{ }; use futures_util::{Stream, StreamExt, TryFutureExt, TryStreamExt}; use helium_proto::services::poc_mobile as proto; +use hextree::disktree::DiskTreeMap; use lazy_static::lazy_static; use regex::Regex; use rust_decimal::prelude::ToPrimitive; @@ -23,13 +24,13 @@ use task_manager::{ManagedTask, TaskManager}; use tokio::{fs::File, io::AsyncWriteExt, time::Instant}; use crate::{ - boosting_oracles::assignment::HexAssignments, coverage::{NewCoverageObjectNotification, SignalLevel}, Settings, }; -use super::{ - footfall::Footfall, landtype::Landtype, urbanization::Urbanization, HexAssignment, HexBoostData, +use hex_assignments::{ + assignment::HexAssignments, footfall::Footfall, landtype::Landtype, urbanization::Urbanization, + HexAssignment, HexBoostData, }; #[async_trait::async_trait] @@ -106,6 +107,72 @@ pub trait DataSet: HexAssignment + Send + Sync + 'static { } } +#[async_trait::async_trait] +impl DataSet for Footfall { + const TYPE: DataSetType = DataSetType::Footfall; + + fn timestamp(&self) -> Option> { + self.timestamp + } + + fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { + self.footfall = Some(DiskTreeMap::open(path)?); + self.timestamp = Some(time_to_use); + Ok(()) + } + + fn is_ready(&self) -> bool { + self.footfall.is_some() + } +} + +#[async_trait::async_trait] +impl DataSet for Landtype { + const TYPE: DataSetType = DataSetType::Landtype; + + fn timestamp(&self) -> Option> { + self.timestamp + } + + fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { + self.landtype = Some(DiskTreeMap::open(path)?); + self.timestamp = Some(time_to_use); + Ok(()) + } + + fn is_ready(&self) -> bool { + self.landtype.is_some() + } +} + +#[async_trait::async_trait] +impl DataSet for Urbanization { + const TYPE: DataSetType = DataSetType::Urbanization; + + fn timestamp(&self) -> Option> { + self.timestamp + } + + fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { + self.urbanized = Some(DiskTreeMap::open(path)?); + self.timestamp = Some(time_to_use); + Ok(()) + } + + fn is_ready(&self) -> bool { + self.urbanized.is_some() + } +} + +pub fn is_hex_boost_data_ready(h: &HexBoostData) -> bool +where + A: DataSet, + B: DataSet, + C: DataSet, +{ + h.urbanization.is_ready() && h.footfall.is_ready() && h.landtype.is_ready() +} + pub struct DataSetDownloaderDaemon { pool: PgPool, data_sets: HexBoostData, @@ -195,9 +262,9 @@ impl DataSetDownloaderDaemon { .create() .await?; - let urbanization = Urbanization::new(); - let footfall = Footfall::new(); - let landtype = Landtype::new(); + let urbanization = Urbanization::new(None); + let footfall = Footfall::new(None); + let landtype = Landtype::new(None); let hex_boost_data = HexBoostData::builder() .footfall(footfall) .landtype(landtype) @@ -268,7 +335,7 @@ where // hex assignments: let new_data_set = new_urbanized.is_some() || new_footfall.is_some() || new_landtype.is_some(); - if self.data_sets.is_ready() && new_data_set { + if is_hex_boost_data_ready(&self.data_sets) && new_data_set { tracing::info!("Processing new data sets"); set_all_oracle_boosting_assignments( &self.pool, @@ -326,7 +393,7 @@ where // Attempt to fill in any unassigned hexes. This is for the edge case in // which we shutdown before a coverage object updates. - if self.data_sets.is_ready() { + if is_hex_boost_data_ready(&self.data_sets) { set_unassigned_oracle_boosting_assignments( &self.pool, &self.data_sets, @@ -342,7 +409,7 @@ where _ = self.new_coverage_object_notification.await_new_coverage_object() => { // If we see a new coverage object, we want to assign only those hexes // that don't have an assignment - if self.data_sets.is_ready() { + if is_hex_boost_data_ready(&self.data_sets) { set_unassigned_oracle_boosting_assignments( &self.pool, &self.data_sets, diff --git a/mobile_verifier/src/boosting_oracles/mod.rs b/mobile_verifier/src/boosting_oracles/mod.rs index 0f63845cb..e1a05b952 100644 --- a/mobile_verifier/src/boosting_oracles/mod.rs +++ b/mobile_verifier/src/boosting_oracles/mod.rs @@ -1,283 +1,2 @@ -pub mod assignment; pub mod data_sets; -pub mod footfall; -pub mod landtype; -pub mod urbanization; - -use std::collections::HashMap; - -use crate::boosting_oracles::assignment::HexAssignments; -pub use assignment::Assignment; pub use data_sets::*; - -pub trait HexAssignment: Send + Sync + 'static { - fn assignment(&self, cell: hextree::Cell) -> anyhow::Result; -} - -impl HexAssignment for HashMap { - fn assignment(&self, cell: hextree::Cell) -> anyhow::Result { - Ok(*self.get(&cell).unwrap()) - } -} - -impl HexAssignment for Assignment { - fn assignment(&self, _cell: hextree::Cell) -> anyhow::Result { - Ok(*self) - } -} - -#[derive(derive_builder::Builder)] -#[builder(pattern = "owned")] -pub struct HexBoostData { - pub footfall: Foot, - pub landtype: Land, - pub urbanization: Urban, -} -impl HexBoostData { - pub fn builder() -> HexBoostDataBuilder { - HexBoostDataBuilder::default() - } -} - -impl HexBoostData -where - Foot: DataSet, - Land: DataSet, - Urban: DataSet, -{ - pub fn is_ready(&self) -> bool { - self.urbanization.is_ready() && self.footfall.is_ready() && self.landtype.is_ready() - } -} - -impl HexBoostData -where - Foot: HexAssignment, - Land: HexAssignment, - Urban: HexAssignment, -{ - pub fn assignments(&self, cell: hextree::Cell) -> anyhow::Result { - HexAssignments::builder(cell) - .footfall(&self.footfall) - .landtype(&self.landtype) - .urbanized(&self.urbanization) - .build() - } -} - -#[cfg(test)] -mod tests { - - use std::io::Cursor; - - use hextree::{disktree::DiskTreeMap, HexTreeMap}; - - use self::{footfall::Footfall, landtype::Landtype, urbanization::Urbanization}; - - use super::*; - - #[test] - fn test_hex_boost_data() -> anyhow::Result<()> { - // This test will break if any of the logic deriving Assignments from - // the underlying DiskTreeMap's changes. - - let unknown_cell = hextree::Cell::from_raw(0x8c2681a3064d9ff)?; - - // Types of Cells - // yellow - POI ≥ 1 Urbanized - let poi_built_urbanized = hextree::Cell::from_raw(0x8c2681a3064dbff)?; - let poi_grass_urbanized = hextree::Cell::from_raw(0x8c2681a3064ddff)?; - let poi_water_urbanized = hextree::Cell::from_raw(0x8c2681a3064e1ff)?; - // orange - POI ≥ 1 Not Urbanized - let poi_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e3ff)?; - let poi_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e5ff)?; - let poi_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a3064e7ff)?; - // light green - Point of Interest Urbanized - let poi_no_data_built_urbanized = hextree::Cell::from_raw(0x8c2681a3064e9ff)?; - let poi_no_data_grass_urbanized = hextree::Cell::from_raw(0x8c2681a3064ebff)?; - let poi_no_data_water_urbanized = hextree::Cell::from_raw(0x8c2681a3064edff)?; - // dark green - Point of Interest Not Urbanized - let poi_no_data_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a306501ff)?; - let poi_no_data_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a306503ff)?; - let poi_no_data_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a306505ff)?; - // light blue - No POI Urbanized - let no_poi_built_urbanized = hextree::Cell::from_raw(0x8c2681a306507ff)?; - let no_poi_grass_urbanized = hextree::Cell::from_raw(0x8c2681a306509ff)?; - let no_poi_water_urbanized = hextree::Cell::from_raw(0x8c2681a30650bff)?; - // dark blue - No POI Not Urbanized - let no_poi_built_not_urbanized = hextree::Cell::from_raw(0x8c2681a30650dff)?; - let no_poi_grass_not_urbanized = hextree::Cell::from_raw(0x8c2681a306511ff)?; - let no_poi_water_not_urbanized = hextree::Cell::from_raw(0x8c2681a306513ff)?; - // gray - Outside of USA - let poi_built_outside_us = hextree::Cell::from_raw(0x8c2681a306515ff)?; - let poi_grass_outside_us = hextree::Cell::from_raw(0x8c2681a306517ff)?; - let poi_water_outside_us = hextree::Cell::from_raw(0x8c2681a306519ff)?; - let poi_no_data_built_outside_us = hextree::Cell::from_raw(0x8c2681a30651bff)?; - let poi_no_data_grass_outside_us = hextree::Cell::from_raw(0x8c2681a30651dff)?; - let poi_no_data_water_outside_us = hextree::Cell::from_raw(0x8c2681a306521ff)?; - let no_poi_built_outside_us = hextree::Cell::from_raw(0x8c2681a306523ff)?; - let no_poi_grass_outside_us = hextree::Cell::from_raw(0x8c2681a306525ff)?; - let no_poi_water_outside_us = hextree::Cell::from_raw(0x8c2681a306527ff)?; - - // Footfall Data - // POI - footfalls > 1 for a POI across hexes - // POI No Data - No footfalls for a POI across any hexes - // NO POI - Does not exist - let mut footfall = HexTreeMap::::new(); - footfall.insert(poi_built_urbanized, 42); - footfall.insert(poi_grass_urbanized, 42); - footfall.insert(poi_water_urbanized, 42); - footfall.insert(poi_built_not_urbanized, 42); - footfall.insert(poi_grass_not_urbanized, 42); - footfall.insert(poi_water_not_urbanized, 42); - footfall.insert(poi_no_data_built_urbanized, 0); - footfall.insert(poi_no_data_grass_urbanized, 0); - footfall.insert(poi_no_data_water_urbanized, 0); - footfall.insert(poi_no_data_built_not_urbanized, 0); - footfall.insert(poi_no_data_grass_not_urbanized, 0); - footfall.insert(poi_no_data_water_not_urbanized, 0); - footfall.insert(poi_built_outside_us, 42); - footfall.insert(poi_grass_outside_us, 42); - footfall.insert(poi_water_outside_us, 42); - footfall.insert(poi_no_data_built_outside_us, 0); - footfall.insert(poi_no_data_grass_outside_us, 0); - footfall.insert(poi_no_data_water_outside_us, 0); - - // Landtype Data - // Map to enum values for Landtype - // An unknown cell is considered Assignment::C - let mut landtype = HexTreeMap::::new(); - landtype.insert(poi_built_urbanized, 50); - landtype.insert(poi_grass_urbanized, 30); - landtype.insert(poi_water_urbanized, 80); - landtype.insert(poi_built_not_urbanized, 50); - landtype.insert(poi_grass_not_urbanized, 30); - landtype.insert(poi_water_not_urbanized, 80); - landtype.insert(poi_no_data_built_urbanized, 50); - landtype.insert(poi_no_data_grass_urbanized, 30); - landtype.insert(poi_no_data_water_urbanized, 80); - landtype.insert(poi_no_data_built_not_urbanized, 50); - landtype.insert(poi_no_data_grass_not_urbanized, 30); - landtype.insert(poi_no_data_water_not_urbanized, 80); - landtype.insert(no_poi_built_urbanized, 50); - landtype.insert(no_poi_grass_urbanized, 30); - landtype.insert(no_poi_water_urbanized, 80); - landtype.insert(no_poi_built_not_urbanized, 50); - landtype.insert(no_poi_grass_not_urbanized, 30); - landtype.insert(no_poi_water_not_urbanized, 80); - landtype.insert(poi_built_outside_us, 50); - landtype.insert(poi_grass_outside_us, 30); - landtype.insert(poi_water_outside_us, 80); - landtype.insert(poi_no_data_built_outside_us, 50); - landtype.insert(poi_no_data_grass_outside_us, 30); - landtype.insert(poi_no_data_water_outside_us, 80); - landtype.insert(no_poi_built_outside_us, 50); - landtype.insert(no_poi_grass_outside_us, 30); - landtype.insert(no_poi_water_outside_us, 80); - - // Urbanized data - // Urban - something in the map, and in the geofence - // Not Urban - nothing in the map, but in the geofence - // Outside - not in the geofence, urbanized hex never considered - let mut urbanized = HexTreeMap::::new(); - urbanized.insert(poi_built_urbanized, 1); - urbanized.insert(poi_grass_urbanized, 1); - urbanized.insert(poi_water_urbanized, 1); - urbanized.insert(poi_no_data_built_urbanized, 1); - urbanized.insert(poi_no_data_grass_urbanized, 1); - urbanized.insert(poi_no_data_water_urbanized, 1); - urbanized.insert(no_poi_built_urbanized, 1); - urbanized.insert(no_poi_grass_urbanized, 1); - urbanized.insert(no_poi_water_urbanized, 1); - - let inside_usa = [ - poi_built_urbanized, - poi_grass_urbanized, - poi_water_urbanized, - poi_built_not_urbanized, - poi_grass_not_urbanized, - poi_water_not_urbanized, - poi_no_data_built_urbanized, - poi_no_data_grass_urbanized, - poi_no_data_water_urbanized, - poi_no_data_built_not_urbanized, - poi_no_data_grass_not_urbanized, - poi_no_data_water_not_urbanized, - no_poi_built_urbanized, - no_poi_grass_urbanized, - no_poi_water_urbanized, - no_poi_built_not_urbanized, - no_poi_grass_not_urbanized, - no_poi_water_not_urbanized, - ]; - for inside_usa in inside_usa.into_iter() { - urbanized.entry(inside_usa).or_insert(0); - } - // These vectors are a standin for the file system - let mut urbanized_buf = vec![]; - let mut footfall_buff = vec![]; - let mut landtype_buf = vec![]; - - // Turn the HexTrees into DiskTrees - urbanized.to_disktree(Cursor::new(&mut urbanized_buf), |w, v| w.write_all(&[*v]))?; - footfall.to_disktree(Cursor::new(&mut footfall_buff), |w, v| w.write_all(&[*v]))?; - landtype.to_disktree(Cursor::new(&mut landtype_buf), |w, v| w.write_all(&[*v]))?; - - let footfall = Footfall::new_mock(DiskTreeMap::with_buf(footfall_buff)?); - let landtype = Landtype::new_mock(DiskTreeMap::with_buf(landtype_buf)?); - let urbanization = Urbanization::new_mock(DiskTreeMap::with_buf(urbanized_buf)?); - - // Let the testing commence - let data = HexBoostData::builder() - .footfall(footfall) - .landtype(landtype) - .urbanization(urbanization) - .build()?; - - // NOTE(mj): formatting ignored to make it easier to see the expected change in assignments. - // NOTE(mj): The semicolon at the end of the block is there to keep rust from - // complaining about attributes on expression being experimental. - #[rustfmt::skip] - { - use Assignment::*; - // yellow - assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: A }, data.assignments(poi_built_urbanized)?); - assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: A }, data.assignments(poi_grass_urbanized)?); - assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: A }, data.assignments(poi_water_urbanized)?); - // orange - assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: B }, data.assignments(poi_built_not_urbanized)?); - assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: B }, data.assignments(poi_grass_not_urbanized)?); - assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: B }, data.assignments(poi_water_not_urbanized)?); - // light green - assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: A }, data.assignments(poi_no_data_built_urbanized)?); - assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: A }, data.assignments(poi_no_data_grass_urbanized)?); - assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: A }, data.assignments(poi_no_data_water_urbanized)?); - // green - assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: B }, data.assignments(poi_no_data_built_not_urbanized)?); - assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: B }, data.assignments(poi_no_data_grass_not_urbanized)?); - assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: B }, data.assignments(poi_no_data_water_not_urbanized)?); - // light blue - assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: A }, data.assignments(no_poi_built_urbanized)?); - assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: A }, data.assignments(no_poi_grass_urbanized)?); - assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: A }, data.assignments(no_poi_water_urbanized)?); - // dark blue - assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: B }, data.assignments(no_poi_built_not_urbanized)?); - assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: B }, data.assignments(no_poi_grass_not_urbanized)?); - assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: B }, data.assignments(no_poi_water_not_urbanized)?); - // gray - assert_eq!(HexAssignments { footfall: A, landtype: A, urbanized: C }, data.assignments(poi_built_outside_us)?); - assert_eq!(HexAssignments { footfall: A, landtype: B, urbanized: C }, data.assignments(poi_grass_outside_us)?); - assert_eq!(HexAssignments { footfall: A, landtype: C, urbanized: C }, data.assignments(poi_water_outside_us)?); - assert_eq!(HexAssignments { footfall: B, landtype: A, urbanized: C }, data.assignments(poi_no_data_built_outside_us)?); - assert_eq!(HexAssignments { footfall: B, landtype: B, urbanized: C }, data.assignments(poi_no_data_grass_outside_us)?); - assert_eq!(HexAssignments { footfall: B, landtype: C, urbanized: C }, data.assignments(poi_no_data_water_outside_us)?); - assert_eq!(HexAssignments { footfall: C, landtype: A, urbanized: C }, data.assignments(no_poi_built_outside_us)?); - assert_eq!(HexAssignments { footfall: C, landtype: B, urbanized: C }, data.assignments(no_poi_grass_outside_us)?); - assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: C }, data.assignments(no_poi_water_outside_us)?); - // never inserted - assert_eq!(HexAssignments { footfall: C, landtype: C, urbanized: C }, data.assignments(unknown_cell)?); - }; - - Ok(()) - } -} diff --git a/mobile_verifier/src/boosting_oracles/urbanization.rs b/mobile_verifier/src/boosting_oracles/urbanization.rs deleted file mode 100644 index 8070c445c..000000000 --- a/mobile_verifier/src/boosting_oracles/urbanization.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::path::Path; - -use chrono::{DateTime, Utc}; -use hextree::disktree::DiskTreeMap; - -use super::{Assignment, DataSet, DataSetType, HexAssignment}; - -pub struct Urbanization { - urbanized: Option, - timestamp: Option>, -} - -impl Urbanization { - pub fn new() -> Self { - Self { - urbanized: None, - timestamp: None, - } - } - - pub fn new_mock(urbanized: DiskTreeMap) -> Self { - Self { - urbanized: Some(urbanized), - timestamp: None, - } - } -} - -impl Default for Urbanization { - fn default() -> Self { - Self::new() - } -} - -#[async_trait::async_trait] -impl DataSet for Urbanization { - const TYPE: DataSetType = DataSetType::Urbanization; - - fn timestamp(&self) -> Option> { - self.timestamp - } - - fn update(&mut self, path: &Path, time_to_use: DateTime) -> anyhow::Result<()> { - self.urbanized = Some(DiskTreeMap::open(path)?); - self.timestamp = Some(time_to_use); - Ok(()) - } - - fn is_ready(&self) -> bool { - self.urbanized.is_some() - } -} - -impl HexAssignment for Urbanization { - fn assignment(&self, cell: hextree::Cell) -> anyhow::Result { - let Some(ref urbanized) = self.urbanized else { - anyhow::bail!("No urbanization data set has been loaded"); - }; - match urbanized.get(cell)? { - Some((_, &[1])) => Ok(Assignment::A), - Some((_, &[0])) => Ok(Assignment::B), - None => Ok(Assignment::C), - Some((_, other)) => { - anyhow::bail!("unexpected urbanization disktree data: {cell:?} {other:?}") - } - } - } -} diff --git a/mobile_verifier/src/cli/verify_disktree.rs b/mobile_verifier/src/cli/verify_disktree.rs index 621b24ad2..ae0204d40 100644 --- a/mobile_verifier/src/cli/verify_disktree.rs +++ b/mobile_verifier/src/cli/verify_disktree.rs @@ -2,10 +2,9 @@ use std::{collections::HashMap, path::PathBuf}; use hextree::disktree::DiskTreeMap; -use crate::{ - boosting_oracles::{landtype::LandtypeValue, Assignment}, - Settings, -}; +use hex_assignments::{landtype::LandtypeValue, Assignment}; + +use crate::Settings; #[derive(Debug, clap::Args)] pub struct Cmd { diff --git a/mobile_verifier/src/coverage.rs b/mobile_verifier/src/coverage.rs index 11dfe7d88..3da4e98b4 100644 --- a/mobile_verifier/src/coverage.rs +++ b/mobile_verifier/src/coverage.rs @@ -1,5 +1,4 @@ use crate::{ - boosting_oracles::assignment::HexAssignments, heartbeats::{HbType, KeyType, OwnedKeyType}, IsAuthorized, Settings, }; @@ -23,6 +22,7 @@ use helium_proto::services::{ mobile_config::NetworkKeyRole, poc_mobile::{self as proto, CoverageObjectValidity, SignalLevel as SignalLevelProto}, }; +use hex_assignments::assignment::HexAssignments; use hextree::Cell; use mobile_config::{ boosted_hex_info::{BoostedHex, BoostedHexes}, @@ -962,8 +962,17 @@ mod test { use super::*; use chrono::NaiveDate; use futures::stream::iter; + use hex_assignments::Assignment; use hextree::Cell; + fn hex_assignments_mock() -> HexAssignments { + HexAssignments { + footfall: Assignment::A, + urbanized: Assignment::A, + landtype: Assignment::A, + } + } + /// Test to ensure that if there are multiple radios with different signal levels /// in a given hex, that the one with the highest signal level is chosen. #[tokio::test] @@ -997,7 +1006,7 @@ mod test { points: CoverageRewardPoints { coverage_points: dec!(100), boost_multiplier: NonZeroU32::new(1).unwrap(), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), rank: None }, boosted_hex_info: BoostedHex { @@ -1031,7 +1040,7 @@ mod test { signal_power: 0, coverage_claim_time, inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), } } @@ -1113,7 +1122,7 @@ mod test { points: CoverageRewardPoints { coverage_points: dec!(100), boost_multiplier: NonZeroU32::new(1).unwrap(), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), rank: None }, boosted_hex_info: BoostedHex { @@ -1157,7 +1166,7 @@ mod test { coverage_points: dec!(4), rank: Some(dec!(1.0)), boost_multiplier: NonZeroU32::new(1).unwrap(), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), }, boosted_hex_info: BoostedHex { location: Cell::from_raw(0x8a1fb46622dffff).expect("valid h3 cell"), @@ -1171,7 +1180,7 @@ mod test { coverage_points: dec!(4), rank: Some(dec!(0.50)), boost_multiplier: NonZeroU32::new(1).unwrap(), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), }, boosted_hex_info: BoostedHex { location: Cell::from_raw(0x8a1fb46622dffff).expect("valid h3 cell"), @@ -1185,7 +1194,7 @@ mod test { coverage_points: dec!(4), rank: Some(dec!(0.25)), boost_multiplier: NonZeroU32::new(1).unwrap(), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), }, boosted_hex_info: BoostedHex { location: Cell::from_raw(0x8a1fb46622dffff).expect("valid h3 cell"), @@ -1456,7 +1465,7 @@ mod test { signal_power: 0, coverage_claim_time: coverage_claim_time.unwrap_or(DateTime::::MIN_UTC), inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), } } @@ -1474,7 +1483,7 @@ mod test { signal_level: SignalLevel::High, coverage_claim_time, inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), } } @@ -1492,7 +1501,7 @@ mod test { signal_level: SignalLevel::High, coverage_claim_time, inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), } } @@ -1510,7 +1519,7 @@ mod test { signal_level, coverage_claim_time, inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), } } } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index b4ddcca62..632df340e 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -696,8 +696,9 @@ pub fn get_scheduled_tokens_for_oracles(duration: Duration) -> Decimal { #[cfg(test)] mod test { use super::*; + use hex_assignments::{assignment::HexAssignments, Assignment}; + use crate::{ - boosting_oracles::assignment::HexAssignments, cell_type::CellType, coverage::{CoveredHexStream, HexCoverage, Seniority}, data_session::{self, HotspotDataSession, HotspotReward}, @@ -718,6 +719,14 @@ mod test { use std::collections::HashMap; use uuid::Uuid; + fn hex_assignments_mock() -> HexAssignments { + HexAssignments { + footfall: Assignment::A, + urbanized: Assignment::A, + landtype: Assignment::A, + } + } + #[test] fn ensure_correct_conversion_of_bytes_to_bones() { assert_eq!( @@ -1006,7 +1015,7 @@ mod test { signal_power: 0, coverage_claim_time: DateTime::::MIN_UTC, inserted_at: DateTime::::MIN_UTC, - assignments: HexAssignments::test_best(), + assignments: hex_assignments_mock(), }] } @@ -1889,7 +1898,7 @@ mod test { coverage_points: CoverageRewardPoints { boost_multiplier: NonZeroU32::new(1).unwrap(), coverage_points: dec!(10.0), - hex_assignments: HexAssignments::test_best(), + hex_assignments: hex_assignments_mock(), rank: None, }, boosted_hex: BoostedHex { diff --git a/mobile_verifier/tests/integrations/boosting_oracles.rs b/mobile_verifier/tests/integrations/boosting_oracles.rs index 3f791d2cc..e56a5afa9 100644 --- a/mobile_verifier/tests/integrations/boosting_oracles.rs +++ b/mobile_verifier/tests/integrations/boosting_oracles.rs @@ -11,9 +11,10 @@ use helium_crypto::PublicKeyBinary; use helium_proto::services::poc_mobile::{ CoverageObjectValidity, OracleBoostingHexAssignment, SignalLevel, }; +use hex_assignments::{Assignment, HexBoostData}; use mobile_config::boosted_hex_info::BoostedHexes; + use mobile_verifier::{ - boosting_oracles::{Assignment, HexBoostData}, coverage::{CoverageClaimTimeCache, CoverageObject, CoverageObjectCache, Seniority}, geofence::GeofenceValidator, heartbeats::{Heartbeat, HeartbeatReward, LocationCache, SeniorityUpdate, ValidatedHeartbeat}, @@ -140,7 +141,7 @@ async fn test_footfall_and_urbanization_report(pool: PgPool) -> anyhow::Result<( let hexes = { // NOTE(mj): Cell is mutated in constructor to keep elements aligned for readability let mut cell = CellIndex::try_from(0x8c2681a3064d9ff)?; - use Assignment::*; + use hex_assignments::Assignment::*; vec![ // yellow - POI ≥ 1 Urbanized new_hex_assingment(&mut cell, A, A, A, 1000), @@ -260,7 +261,7 @@ async fn test_footfall_and_urbanization_and_landtype(pool: PgPool) -> anyhow::Re let hexes = { // NOTE(mj): Cell is mutated in constructor to keep elements aligned for readability let mut cell = CellIndex::try_from(0x8c2681a3064d9ff)?; - use Assignment::*; + use hex_assignments::Assignment::*; vec![ // yellow - POI ≥ 1 Urbanized TestHex::new(&mut cell, A, A, A, 400), diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 5722f6a7a..9195ad00a 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -12,13 +12,13 @@ use helium_proto::{ }, Message, }; +use hex_assignments::{Assignment, HexAssignment, HexBoostData}; use mobile_config::{ boosted_hex_info::{BoostedHexInfo, BoostedHexInfoStream}, client::{hex_boosting_client::HexBoostingInfoResolver, ClientError}, }; -use mobile_verifier::boosting_oracles::{ - AssignedCoverageObjects, Assignment, HexAssignment, HexBoostData, -}; + +use mobile_verifier::boosting_oracles::AssignedCoverageObjects; use rust_decimal::prelude::ToPrimitive; use rust_decimal_macros::dec; use sqlx::PgPool;