Skip to content

Commit 62bde0f

Browse files
committed
Update cache to hydrate on new
Remove rewarder part to put in diff PR
1 parent 1004ffb commit 62bde0f

File tree

8 files changed

+99
-93
lines changed

8 files changed

+99
-93
lines changed

mobile_verifier/src/cli/server.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl Cmd {
105105
let (new_coverage_obj_notifier, new_coverage_obj_notification) =
106106
new_coverage_object_notification_channel();
107107

108-
let location_cache = LocationCache::new(&pool);
108+
let location_cache = LocationCache::new(&pool).await?;
109109

110110
TaskManager::builder()
111111
.add_task(file_upload_server)

mobile_verifier/src/heartbeats/location_cache.rs

+82-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use chrono::{DateTime, Duration, Utc};
22
use file_store::radio_location_estimates::Entity;
3+
use futures::StreamExt;
34
use helium_crypto::PublicKeyBinary;
4-
use sqlx::PgPool;
5-
use std::{collections::HashMap, sync::Arc};
5+
use sqlx::{PgPool, Row};
6+
use std::{collections::HashMap, str::FromStr, sync::Arc};
67
use tokio::sync::{Mutex, MutexGuard};
78

89
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
@@ -39,15 +40,18 @@ pub struct LocationCache {
3940
}
4041

4142
impl LocationCache {
42-
pub fn new(pool: &PgPool) -> Self {
43+
pub async fn new(pool: &PgPool) -> anyhow::Result<Self> {
4344
let wifi = Arc::new(Mutex::new(HashMap::new()));
4445
let cbrs = Arc::new(Mutex::new(HashMap::new()));
45-
// TODO: We could spawn an hydrate from DB here?
46-
Self {
46+
47+
hydrate_wifi(pool, &wifi).await?;
48+
hydrate_cbrs(pool, &cbrs).await?;
49+
50+
Ok(Self {
4751
pool: pool.clone(),
4852
wifi,
4953
cbrs,
50-
}
54+
})
5155
}
5256

5357
pub async fn get(&self, key: LocationCacheKey) -> anyhow::Result<Option<LocationCacheValue>> {
@@ -165,7 +169,7 @@ impl LocationCache {
165169
FROM cbrs_heartbeats
166170
WHERE latest_timestamp IS NOT NULL
167171
AND latest_timestamp >= $1
168-
AND hotspot_key = $2
172+
AND cbsd_id = $2
169173
ORDER BY latest_timestamp DESC
170174
LIMIT 1
171175
"#,
@@ -187,6 +191,77 @@ impl LocationCache {
187191
}
188192
}
189193

194+
async fn hydrate_wifi(pool: &PgPool, mutex: &Arc<Mutex<LocationCacheData>>) -> anyhow::Result<()> {
195+
let mut rows = sqlx::query(
196+
r#"
197+
SELECT wh.lat, wh.lon, wh.location_validation_timestamp AS timestamp, wh.hotspot_key
198+
FROM wifi_heartbeats wh
199+
JOIN (
200+
SELECT hotspot_key, MAX(location_validation_timestamp) AS max_timestamp
201+
FROM wifi_heartbeats
202+
WHERE location_validation_timestamp IS NOT NULL
203+
GROUP BY hotspot_key
204+
) latest ON wh.hotspot_key = latest.hotspot_key
205+
AND wh.location_validation_timestamp = latest.max_timestamp
206+
"#,
207+
)
208+
.fetch(pool);
209+
210+
while let Some(row_result) = rows.next().await {
211+
let row = row_result?;
212+
213+
let hotspot_key: String = row.get("hotspot_key");
214+
let pub_key_bin = PublicKeyBinary::from_str(&hotspot_key)?;
215+
let key = LocationCacheKey::WifiPubKey(pub_key_bin);
216+
217+
let value = LocationCacheValue {
218+
lat: row.get("lat"),
219+
lon: row.get("lon"),
220+
timestamp: row.get("timestamp"),
221+
};
222+
223+
let mut data = mutex.lock().await;
224+
data.insert(key.clone(), value);
225+
}
226+
227+
Ok(())
228+
}
229+
230+
async fn hydrate_cbrs(pool: &PgPool, mutex: &Arc<Mutex<LocationCacheData>>) -> anyhow::Result<()> {
231+
let mut rows = sqlx::query(
232+
r#"
233+
SELECT ch.lat, ch.lon, ch.latest_timestamp AS timestamp, ch.cbsd_id
234+
FROM cbrs_heartbeats ch
235+
JOIN (
236+
SELECT cbsd_id, MAX(latest_timestamp) AS max_timestamp
237+
FROM cbrs_heartbeats
238+
WHERE latest_timestamp IS NOT NULL
239+
GROUP BY cbsd_id
240+
) latest ON ch.cbsd_id = latest.cbsd_id
241+
AND ch.latest_timestamp = latest.max_timestamp
242+
"#,
243+
)
244+
.fetch(pool);
245+
246+
while let Some(row_result) = rows.next().await {
247+
let row = row_result?;
248+
249+
let id: String = row.get("cbsd_id");
250+
let key = LocationCacheKey::CbrsId(id);
251+
252+
let value = LocationCacheValue {
253+
lat: row.get("lat"),
254+
lon: row.get("lon"),
255+
timestamp: row.get("timestamp"),
256+
};
257+
258+
let mut data = mutex.lock().await;
259+
data.insert(key.clone(), value);
260+
}
261+
262+
Ok(())
263+
}
264+
190265
pub fn key_to_entity(entity: LocationCacheKey) -> Entity {
191266
match entity {
192267
LocationCacheKey::CbrsId(id) => Entity::CbrsId(id),

mobile_verifier/src/rewarder.rs

+2-71
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@ use self::boosted_hex_eligibility::BoostedHexEligibility;
22
use crate::{
33
boosting_oracles::db::check_for_unprocessed_data_sets,
44
coverage, data_session,
5-
heartbeats::{
6-
self,
7-
location_cache::{self, LocationCache},
8-
HeartbeatReward,
9-
},
5+
heartbeats::{self, location_cache::LocationCache, HeartbeatReward},
106
radio_location_estimates, radio_threshold,
117
reward_shares::{
128
self, CalculatedPocRewardShares, CoverageShares, DataTransferAndPocAllocatedRewardBuckets,
@@ -25,7 +21,6 @@ use file_store::{
2521
traits::{FileSinkCommitStrategy, FileSinkRollTime, FileSinkWriteExt, TimestampEncode},
2622
};
2723
use futures_util::TryFutureExt;
28-
use h3o::{LatLng, Resolution};
2924
use helium_proto::{
3025
reward_manifest::RewardData::MobileRewardData,
3126
services::poc_mobile::{
@@ -433,7 +428,7 @@ async fn reward_poc(
433428
speedtest_avg_sink: &FileSinkClient<proto::SpeedtestAvg>,
434429
reward_period: &Range<DateTime<Utc>>,
435430
reward_shares: DataTransferAndPocAllocatedRewardBuckets,
436-
location_cache: &LocationCache,
431+
_location_cache: &LocationCache,
437432
) -> anyhow::Result<(Decimal, CalculatedPocRewardShares)> {
438433
let heartbeats = HeartbeatReward::validated(pool, reward_period);
439434
let speedtest_averages =
@@ -460,30 +455,6 @@ async fn reward_poc(
460455
)
461456
.await?;
462457

463-
{
464-
// TODO: Maybe we should hydrate cache on start to avoid banning too many hotspot
465-
let locations = location_cache.get_all().await;
466-
for (key, value) in locations.iter() {
467-
let entity = location_cache::key_to_entity(key.clone());
468-
// Estimates are ordered by bigger radius first it should allow us to do less calculation
469-
// and find a match faster
470-
let estimates =
471-
radio_location_estimates::get_valid_estimates(pool, &entity, dec!(0.75)).await?;
472-
if estimates.is_empty() {
473-
// TODO we ban that key
474-
todo!()
475-
} else {
476-
match is_within_radius(value.lat, value.lon, estimates) {
477-
Ok(true) => todo!(),
478-
// TODO we ban that key
479-
Ok(false) => todo!(),
480-
// TODO we ban that key
481-
Err(_) => todo!(),
482-
}
483-
}
484-
}
485-
}
486-
487458
let coverage_shares = CoverageShares::new(
488459
pool,
489460
heartbeats,
@@ -530,46 +501,6 @@ async fn reward_poc(
530501
Ok((unallocated_poc_amount, calculated_poc_rewards_per_share))
531502
}
532503

533-
fn is_within_radius(
534-
loc_lat: f64,
535-
loc_lon: f64,
536-
estimates: Vec<(Decimal, Decimal, Decimal)>,
537-
) -> anyhow::Result<bool> {
538-
let resolution = Resolution::Twelve;
539-
540-
let point_a = LatLng::new(loc_lat, loc_lon)
541-
.map_err(|e| anyhow::anyhow!("Invalid LatLng for A: {}", e))?;
542-
let h3_index_a = point_a.to_cell(resolution);
543-
544-
for (radius_meters, lat, lon) in estimates {
545-
let lat_f64 = lat
546-
.to_f64()
547-
.ok_or_else(|| anyhow::anyhow!("Failed to convert lat_b to f64"))?;
548-
let lon_f64 = lon
549-
.to_f64()
550-
.ok_or_else(|| anyhow::anyhow!("Failed to convert lon_b to f64"))?;
551-
let radius_meters_f64 = radius_meters
552-
.to_f64()
553-
.ok_or_else(|| anyhow::anyhow!("Failed to convert radius_meters to f64"))?;
554-
555-
let point_b = LatLng::new(lat_f64, lon_f64)
556-
.map_err(|e| anyhow::anyhow!("Invalid LatLng for B: {}", e))?;
557-
let h3_index_b = point_b.to_cell(resolution);
558-
559-
let grid_distance = h3_index_a
560-
.grid_distance(h3_index_b)
561-
.map_err(|e| anyhow::anyhow!("Failed to calculate grid distance: {}", e))?;
562-
563-
let max_grid_distance = (radius_meters_f64 / 9.0).round() as i32;
564-
565-
if grid_distance <= max_grid_distance {
566-
return Ok(true);
567-
}
568-
}
569-
570-
Ok(false)
571-
}
572-
573504
pub async fn reward_dc(
574505
mobile_rewards: &FileSinkClient<proto::MobileRewardShare>,
575506
reward_period: &Range<DateTime<Utc>>,

mobile_verifier/tests/integrations/boosting_oracles.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ async fn test_footfall_and_urbanization_and_landtype(pool: PgPool) -> anyhow::Re
338338

339339
let coverage_objects = CoverageObjectCache::new(&pool);
340340
let coverage_claim_time_cache = CoverageClaimTimeCache::new();
341-
let location_cache = LocationCache::new(&pool);
341+
let location_cache = LocationCache::new(&pool).await?;
342342

343343
let epoch = start..end;
344344
let mut heartbeats = pin!(ValidatedHeartbeat::validate_heartbeats(

mobile_verifier/tests/integrations/hex_boosting.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> {
137137
.to_u64()
138138
.unwrap();
139139

140-
let location_cache = LocationCache::new(&pool);
140+
let location_cache = LocationCache::new(&pool).await?;
141141

142142
let (_, rewards) = tokio::join!(
143143
// run rewards for poc and dc
@@ -323,7 +323,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu
323323
];
324324

325325
let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes);
326-
let location_cache = LocationCache::new(&pool);
326+
let location_cache = LocationCache::new(&pool).await?;
327327
let (_, rewards) = tokio::join!(
328328
// run rewards for poc and dc
329329
rewarder::reward_poc_and_dc(
@@ -488,7 +488,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res
488488

489489
let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes);
490490

491-
let location_cache = LocationCache::new(&pool);
491+
let location_cache = LocationCache::new(&pool).await?;
492492

493493
let (_, rewards) = tokio::join!(
494494
// run rewards for poc and dc
@@ -665,7 +665,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> {
665665
];
666666

667667
let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes);
668-
let location_cache = LocationCache::new(&pool);
668+
let location_cache = LocationCache::new(&pool).await?;
669669
let (_, rewards) = tokio::join!(
670670
// run rewards for poc and dc
671671
rewarder::reward_poc_and_dc(
@@ -799,7 +799,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow:
799799
.to_u64()
800800
.unwrap();
801801

802-
let location_cache = LocationCache::new(&pool);
802+
let location_cache = LocationCache::new(&pool).await?;
803803
let (_, rewards) = tokio::join!(
804804
// run rewards for poc and dc
805805
rewarder::reward_poc_and_dc(
@@ -980,7 +980,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust(
980980
let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration)
981981
.to_u64()
982982
.unwrap();
983-
let location_cache = LocationCache::new(&pool);
983+
let location_cache = LocationCache::new(&pool).await?;
984984
let (_, rewards) = tokio::join!(
985985
// run rewards for poc and dc
986986
rewarder::reward_poc_and_dc(
@@ -1187,7 +1187,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an
11871187
.to_u64()
11881188
.unwrap();
11891189

1190-
let location_cache = LocationCache::new(&pool);
1190+
let location_cache = LocationCache::new(&pool).await?;
11911191
let (_, rewards) = tokio::join!(
11921192
// run rewards for poc and dc
11931193
rewarder::reward_poc_and_dc(

mobile_verifier/tests/integrations/last_location.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async fn heartbeat_uses_last_good_location_when_invalid_location(
3939
let epoch_end = epoch_start + Duration::days(2);
4040

4141
let coverage_objects = CoverageObjectCache::new(&pool);
42-
let location_cache = LocationCache::new(&pool);
42+
let location_cache = LocationCache::new(&pool).await?;
4343

4444
let mut transaction = pool.begin().await?;
4545
let coverage_object = coverage_object(&hotspot, &mut transaction).await?;
@@ -101,7 +101,7 @@ async fn heartbeat_will_use_last_good_location_from_db(pool: PgPool) -> anyhow::
101101
let epoch_end = epoch_start + Duration::days(2);
102102

103103
let coverage_objects = CoverageObjectCache::new(&pool);
104-
let location_cache = LocationCache::new(&pool);
104+
let location_cache = LocationCache::new(&pool).await?;
105105

106106
let mut transaction = pool.begin().await?;
107107
let coverage_object = coverage_object(&hotspot, &mut transaction).await?;
@@ -173,7 +173,7 @@ async fn heartbeat_does_not_use_last_good_location_when_more_than_12_hours(
173173
let epoch_end = epoch_start + Duration::days(2);
174174

175175
let coverage_objects = CoverageObjectCache::new(&pool);
176-
let location_cache = LocationCache::new(&pool);
176+
let location_cache = LocationCache::new(&pool).await?;
177177

178178
let mut transaction = pool.begin().await?;
179179
let coverage_object = coverage_object(&hotspot, &mut transaction).await?;

mobile_verifier/tests/integrations/modeled_coverage.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ async fn process_input(
378378
) -> anyhow::Result<()> {
379379
let coverage_objects = CoverageObjectCache::new(pool);
380380
let coverage_claim_time_cache = CoverageClaimTimeCache::new();
381-
let location_cache = LocationCache::new(pool);
381+
let location_cache = LocationCache::new(pool).await?;
382382

383383
let mut transaction = pool.begin().await?;
384384
let mut coverage_objs = pin!(CoverageObject::validate_coverage_objects(
@@ -1376,7 +1376,7 @@ async fn ensure_lower_trust_score_for_distant_heartbeats(pool: PgPool) -> anyhow
13761376

13771377
let max_covered_distance = 5_000;
13781378
let coverage_object_cache = CoverageObjectCache::new(&pool);
1379-
let location_cache = LocationCache::new(&pool);
1379+
let location_cache = LocationCache::new(&pool).await?;
13801380

13811381
let mk_heartbeat = |latlng: LatLng| WifiHeartbeatIngestReport {
13821382
report: WifiHeartbeat {

mobile_verifier/tests/integrations/rewarder_poc_dc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> {
4444
let boosted_hexes = vec![];
4545

4646
let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes);
47-
let location_cache = LocationCache::new(&pool);
47+
let location_cache = LocationCache::new(&pool).await?;
4848
let (_, rewards) = tokio::join!(
4949
// run rewards for poc and dc
5050
rewarder::reward_poc_and_dc(

0 commit comments

Comments
 (0)