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

Modeled Coverage Phase 1 #619

Merged
merged 32 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1cfff2a
Modeled coverage phase 1
maplant Aug 28, 2023
aeb9e0a
Address comments
maplant Aug 29, 2023
cc4d148
Fmt
maplant Aug 29, 2023
45379ac
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Aug 31, 2023
c1015e7
Fix error in test that snuck in somehow
maplant Aug 31, 2023
d9d0126
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Sep 1, 2023
7efabf0
Add on conflict to hex_coverage insertion
maplant Sep 5, 2023
0a32b19
Check if hex_coverage is empty in coalesce
maplant Sep 11, 2023
188aada
Remove duplicate hex coverage checks for testing
maplant Sep 12, 2023
73e7f85
Move to invalidating previous coverage objects
maplant Sep 14, 2023
cf8edd7
Add is null check for invalidated_at in update
maplant Sep 15, 2023
7e4afbb
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Oct 6, 2023
1ab933c
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Oct 30, 2023
19b2cea
Fix up MC Phase 1 to handle wifi coverage objects
maplant Nov 1, 2023
8a724d4
Make coverage objects optional for phase 1
maplant Nov 1, 2023
c5d32b0
Fix iot-beacon-report
maplant Nov 1, 2023
6ae5347
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Nov 6, 2023
f7f0efb
Update to master
maplant Nov 6, 2023
f23889c
Fix seniority updates
maplant Nov 6, 2023
504eddb
make radio_type a postgres enum
maplant Nov 6, 2023
04c233a
Fix insertion of coverage objects
maplant Nov 6, 2023
b88952d
Add prefix
maplant Nov 7, 2023
5cc0ed4
make clippy happy
bbalser Nov 7, 2023
8359c45
Fix key column name
maplant Nov 7, 2023
1fdf088
Merge branch 'map/mc-p1' of github.com:helium/oracles into map/mc-p1
maplant Nov 7, 2023
3cb54eb
s/fetch_one/execute/g
maplant Nov 7, 2023
33ee356
Add test for seniority updates
maplant Nov 7, 2023
2d62fdb
add more integration tests
maplant Nov 7, 2023
632f19f
Don't use select star
maplant Nov 7, 2023
488d62c
Expand modeled_coverage tests to include caches
maplant Nov 8, 2023
60044f5
One more test
maplant Nov 8, 2023
d31f9ef
Merge remote-tracking branch 'origin/main' into map/mc-p1
maplant Nov 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ prost = "*"
once_cell = "1"
lazy_static = "1"
config = {version="0", default-features=false, features=["toml"]}
h3o = "0"
h3o = {version = "0", features = ["serde"]}
xorf = {version = "0", features = ["serde"] }
bytes = "*"
structopt = "0"
Expand All @@ -102,6 +102,7 @@ data-credits = {git = "https://github.com/helium/helium-program-library.git", ta
helium-sub-daos = {git = "https://github.com/helium/helium-program-library.git", tag = "v0.1.0"}
price-oracle = {git = "https://github.com/helium/helium-program-library.git", tag = "v0.1.0"}
tokio-util = "0"
uuid = {version = "1", features = ["v4", "serde"]}
tower-http = {version = "0", features = ["trace"]}

[patch.crates-io]
Expand Down
2 changes: 2 additions & 0 deletions file_store/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ sqlx = {workspace = true}
async-trait = {workspace = true}
derive_builder = "0"
retainer = {workspace = true}
uuid = {workspace = true}
h3o = {workspace = true}
task-manager = { path = "../task_manager" }

[dev-dependencies]
Expand Down
127 changes: 127 additions & 0 deletions file_store/src/coverage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use crate::{
error::DecodeError,
traits::{MsgDecode, TimestampDecode},
Error, Result,
};
use chrono::{DateTime, Utc};
use helium_crypto::PublicKeyBinary;
use helium_proto::services::poc_mobile::{
coverage_object_req_v1, CoverageObjectIngestReportV1, CoverageObjectReqV1,
RadioHexSignalLevel as RadioHexSignalLevelProto, SignalLevel,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RadioHexSignalLevel {
pub location: h3o::CellIndex,
pub signal_level: SignalLevel,
pub signal_power: i32,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum KeyType {
CbsdId(String),
HotspotKey(PublicKeyBinary),
}

impl From<KeyType> for coverage_object_req_v1::KeyType {
fn from(kt: KeyType) -> Self {
match kt {
KeyType::CbsdId(id) => coverage_object_req_v1::KeyType::CbsdId(id),
KeyType::HotspotKey(key) => coverage_object_req_v1::KeyType::HotspotKey(key.into()),
}
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CoverageObject {
pub pub_key: PublicKeyBinary,
pub uuid: Uuid,
pub key_type: KeyType,
pub coverage_claim_time: DateTime<Utc>,
pub coverage: Vec<RadioHexSignalLevel>,
pub indoor: bool,
pub trust_score: u32,
pub signature: Vec<u8>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CoverageObjectIngestReport {
pub received_timestamp: DateTime<Utc>,
pub report: CoverageObject,
}

impl MsgDecode for CoverageObject {
type Msg = CoverageObjectReqV1;
}

impl MsgDecode for CoverageObjectIngestReport {
type Msg = CoverageObjectIngestReportV1;
}

impl TryFrom<CoverageObjectIngestReportV1> for CoverageObjectIngestReport {
type Error = Error;

fn try_from(v: CoverageObjectIngestReportV1) -> Result<Self> {
Ok(Self {
received_timestamp: v.received_timestamp.to_timestamp_millis()?,
report: v
.report
.ok_or_else(|| Error::not_found("ingest coverage object report"))?
.try_into()?,
})
}
}

impl TryFrom<CoverageObjectReqV1> for CoverageObject {
type Error = Error;

fn try_from(v: CoverageObjectReqV1) -> Result<Self> {
let coverage: Result<Vec<RadioHexSignalLevel>> = v
.coverage
.into_iter()
.map(RadioHexSignalLevel::try_from)
.collect();
Ok(Self {
pub_key: v.pub_key.into(),
uuid: Uuid::from_slice(&v.uuid).map_err(DecodeError::from)?,
key_type: match v.key_type {
Some(coverage_object_req_v1::KeyType::CbsdId(id)) => KeyType::CbsdId(id),
Some(coverage_object_req_v1::KeyType::HotspotKey(key)) => {
KeyType::HotspotKey(key.into())
}
None => return Err(Error::NotFound("key_type".to_string())),
},
coverage_claim_time: v.coverage_claim_time.to_timestamp()?,
coverage: coverage?,
indoor: v.indoor,
trust_score: v.trust_score,
signature: v.signature,
})
}
}

impl TryFrom<RadioHexSignalLevelProto> for RadioHexSignalLevel {
type Error = Error;

fn try_from(v: RadioHexSignalLevelProto) -> Result<Self> {
Ok(Self {
signal_level: SignalLevel::from_i32(v.signal_level).ok_or_else(|| {
DecodeError::unsupported_signal_level("coverage_object_req_v1", v.signal_level)
})?,
signal_power: v.signal_power,
location: v.location.parse().map_err(DecodeError::from)?,
})
}
}

impl From<RadioHexSignalLevel> for RadioHexSignalLevelProto {
fn from(rhsl: RadioHexSignalLevel) -> RadioHexSignalLevelProto {
RadioHexSignalLevelProto {
signal_level: rhsl.signal_level as i32,
signal_power: rhsl.signal_power,
location: rhsl.location.to_string(),
}
}
}
10 changes: 10 additions & 0 deletions file_store/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ pub enum DecodeError {
UnsupportedParticipantSide(String, i32),
#[error("unsupported verification status, type: {0}, value: {1}")]
UnsupportedStatusReason(String, i32),
#[error("unsupported signal level, type: {0}, value: {1}")]
UnsupportedSignalLevel(String, i32),
#[error("invalid unix timestamp {0}")]
InvalidTimestamp(u64),
#[error("Uuid error: {0}")]
UuidError(#[from] uuid::Error),
#[error("Invalid cell index error: {0}")]
InvalidCellIndexError(#[from] h3o::error::InvalidCellIndex),
#[error("unsupported packet type, type: {0}, value: {1}")]
UnsupportedPacketType(String, i32),
#[error("file stream try decode error: {0}")]
Expand Down Expand Up @@ -142,6 +148,10 @@ impl DecodeError {
Error::Decode(Self::UnsupportedInvalidReason(msg1.to_string(), msg2))
}

pub fn unsupported_signal_level(msg1: impl ToString, msg2: i32) -> Error {
Error::Decode(Self::UnsupportedSignalLevel(msg1.to_string(), msg2))
}

pub fn file_stream_try_decode<E: ToString>(msg: E) -> Error {
Error::Decode(Self::FileStreamTryDecode(msg.to_string()))
}
Expand Down
10 changes: 10 additions & 0 deletions file_store/src/file_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ pub const VALID_DATA_TRANSFER_SESSION: &str = "valid_data_transfer_session";
pub const PRICE_REPORT: &str = "price_report";
pub const MOBILE_REWARD_SHARE: &str = "mobile_reward_share";
pub const MAPPER_MSG: &str = "mapper_msg";
pub const COVERAGE_OBJECT: &str = "coverage_object";
pub const COVERAGE_OBJECT_INGEST_REPORT: &str = "coverage_object_ingest_report";
pub const SENIORITY_UPDATE: &str = "seniority_update";

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Copy, strum::EnumCount)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -177,7 +179,9 @@ pub enum FileType {
SubscriberLocationIngestReport,
VerifiedSubscriberLocationIngestReport,
MapperMsg,
CoverageObject,
CoverageObjectIngestReport,
SeniorityUpdate,
VerifiedSpeedtest,
WifiHeartbeat,
WifiHeartbeatIngestReport,
Expand Down Expand Up @@ -224,7 +228,9 @@ impl fmt::Display for FileType {
Self::PriceReport => PRICE_REPORT,
Self::MobileRewardShare => MOBILE_REWARD_SHARE,
Self::MapperMsg => MAPPER_MSG,
Self::CoverageObject => COVERAGE_OBJECT,
Self::CoverageObjectIngestReport => COVERAGE_OBJECT_INGEST_REPORT,
Self::SeniorityUpdate => SENIORITY_UPDATE,
};
f.write_str(s)
}
Expand Down Expand Up @@ -271,7 +277,9 @@ impl FileType {
Self::PriceReport => PRICE_REPORT,
Self::MobileRewardShare => MOBILE_REWARD_SHARE,
Self::MapperMsg => MAPPER_MSG,
Self::CoverageObject => COVERAGE_OBJECT,
Self::CoverageObjectIngestReport => COVERAGE_OBJECT_INGEST_REPORT,
Self::SeniorityUpdate => SENIORITY_UPDATE,
}
}
}
Expand Down Expand Up @@ -318,7 +326,9 @@ impl FromStr for FileType {
PRICE_REPORT => Self::PriceReport,
MOBILE_REWARD_SHARE => Self::MobileRewardShare,
MAPPER_MSG => Self::MapperMsg,
COVERAGE_OBJECT => Self::CoverageObject,
COVERAGE_OBJECT_INGEST_REPORT => Self::CoverageObjectIngestReport,
SENIORITY_UPDATE => Self::SeniorityUpdate,
_ => return Err(Error::from(io::Error::from(io::ErrorKind::InvalidInput))),
};
Ok(result)
Expand Down
9 changes: 9 additions & 0 deletions file_store/src/heartbeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use chrono::{DateTime, Utc};
use helium_crypto::PublicKeyBinary;
use helium_proto::services::poc_mobile::{CellHeartbeatIngestReportV1, CellHeartbeatReqV1};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CbrsHeartbeat {
Expand All @@ -18,6 +19,13 @@ pub struct CbrsHeartbeat {
pub operation_mode: bool,
pub cbsd_category: String,
pub cbsd_id: String,
pub coverage_object: Vec<u8>,
}

impl CbrsHeartbeat {
pub fn coverage_object(&self) -> Option<Uuid> {
Uuid::from_slice(&self.coverage_object).ok()
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -47,6 +55,7 @@ impl TryFrom<CellHeartbeatReqV1> for CbrsHeartbeat {
operation_mode: v.operation_mode,
cbsd_category: v.cbsd_category,
cbsd_id: v.cbsd_id,
coverage_object: v.coverage_object,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions file_store/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod cli;
pub mod coverage;
pub mod entropy_report;
mod error;
mod file_info;
Expand Down
1 change: 1 addition & 0 deletions mobile_verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ price = {path = "../price"}
rand = {workspace = true}
async-trait = {workspace = true}
retainer = {workspace = true}
uuid = {workspace = true}
37 changes: 37 additions & 0 deletions mobile_verifier/migrations/17_modeled_coverage.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
CREATE TYPE signal_level AS ENUM (
'none',
'low',
'medium',
'high'
);

CREATE TYPE radio_type as ENUM (
'cbrs',
'wifi'
);

CREATE TABLE hex_coverage (
uuid UUID NOT NULL,
hex BIGINT NOT NULL,
indoor BOOLEAN NOT NULL,
radio_key TEXT NOT NULL,
signal_level signal_level NOT NULL,
coverage_claim_time TIMESTAMPTZ NOT NULL,
inserted_at TIMESTAMPTZ NOT NULL,
radio_type radio_type NOT NULL,
PRIMARY KEY (uuid, hex)
);

CREATE TABLE seniority (
radio_key TEXT NOT NULL,
seniority_ts TIMESTAMPTZ NOT NULL,
last_heartbeat TIMESTAMPTZ NOT NULL,
uuid UUID NOT NULL,
update_reason INT NOT NULL,
inserted_at TIMESTAMPTZ NOT NULL,
radio_type radio_type NOT NULL,
PRIMARY KEY (radio_key, radio_type, seniority_ts)
);

ALTER TABLE wifi_heartbeats ADD COLUMN coverage_object UUID;
ALTER TABLE cbrs_heartbeats ADD COLUMN coverage_object UUID;
1 change: 1 addition & 0 deletions mobile_verifier/migrations/18_invalidated_at.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hex_coverage ADD COLUMN invalidated_at TIMESTAMPTZ;
2 changes: 1 addition & 1 deletion mobile_verifier/src/cell_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub const CELLTYPE_SERCCOMM_OUTDOOR: &str = "P27-SCO4255PA10";
#[derive(Debug, Eq, Hash, PartialEq, Copy, Clone, Serialize, sqlx::Type)]
#[sqlx(type_name = "cell_type")]
#[sqlx(rename_all = "lowercase")]

pub enum CellType {
Nova436H = 0,
Nova430I = 1,
Expand All @@ -23,6 +22,7 @@ pub enum CellType {
CellTypeNone = 5,
NovaGenericWifiIndoor = 6,
}

#[derive(PartialEq)]
pub enum CellTypeLabel {
CellTypeLabelNone = 0,
Expand Down
Loading