@@ -2,7 +2,11 @@ use self::boosted_hex_eligibility::BoostedHexEligibility;
22use crate :: {
33 boosting_oracles:: db:: check_for_unprocessed_data_sets,
44 coverage, data_session,
5- heartbeats:: { self , location_cache:: LocationCache , HeartbeatReward } ,
5+ heartbeats:: {
6+ self ,
7+ location_cache:: { self , LocationCache } ,
8+ HeartbeatReward ,
9+ } ,
610 radio_location_estimates, radio_threshold,
711 reward_shares:: {
812 self , CalculatedPocRewardShares , CoverageShares , DataTransferAndPocAllocatedRewardBuckets ,
@@ -21,6 +25,7 @@ use file_store::{
2125 traits:: { FileSinkCommitStrategy , FileSinkRollTime , FileSinkWriteExt , TimestampEncode } ,
2226} ;
2327use futures_util:: TryFutureExt ;
28+ use h3o:: { LatLng , Resolution } ;
2429use helium_proto:: {
2530 reward_manifest:: RewardData :: MobileRewardData ,
2631 services:: poc_mobile:: {
@@ -428,7 +433,7 @@ async fn reward_poc(
428433 speedtest_avg_sink : & FileSinkClient < proto:: SpeedtestAvg > ,
429434 reward_period : & Range < DateTime < Utc > > ,
430435 reward_shares : DataTransferAndPocAllocatedRewardBuckets ,
431- _location_cache : & LocationCache ,
436+ location_cache : & LocationCache ,
432437) -> anyhow:: Result < ( Decimal , CalculatedPocRewardShares ) > {
433438 let heartbeats = HeartbeatReward :: validated ( pool, reward_period) ;
434439 let speedtest_averages =
@@ -455,6 +460,29 @@ async fn reward_poc(
455460 )
456461 . await ?;
457462
463+ {
464+ let locations = location_cache. get_all ( ) . await ;
465+ for ( key, value) in locations. iter ( ) {
466+ let entity = location_cache:: key_to_entity ( key. clone ( ) ) ;
467+ // Estimates are ordered by bigger radius first it should allow us to do less calculation
468+ // and find a match faster
469+ let estimates =
470+ radio_location_estimates:: get_valid_estimates ( pool, & entity, dec ! ( 0.75 ) ) . await ?;
471+ if estimates. is_empty ( ) {
472+ // TODO we ban that key
473+ todo ! ( )
474+ } else {
475+ match is_within_radius ( value. lat , value. lon , estimates) {
476+ Ok ( true ) => todo ! ( ) ,
477+ // TODO we ban that key
478+ Ok ( false ) => todo ! ( ) ,
479+ // TODO we ban that key
480+ Err ( _) => todo ! ( ) ,
481+ }
482+ }
483+ }
484+ }
485+
458486 let coverage_shares = CoverageShares :: new (
459487 pool,
460488 heartbeats,
@@ -501,6 +529,46 @@ async fn reward_poc(
501529 Ok ( ( unallocated_poc_amount, calculated_poc_rewards_per_share) )
502530}
503531
532+ fn is_within_radius (
533+ loc_lat : f64 ,
534+ loc_lon : f64 ,
535+ estimates : Vec < ( Decimal , Decimal , Decimal ) > ,
536+ ) -> anyhow:: Result < bool > {
537+ let resolution = Resolution :: Twelve ;
538+
539+ let point_a = LatLng :: new ( loc_lat, loc_lon)
540+ . map_err ( |e| anyhow:: anyhow!( "Invalid LatLng for A: {}" , e) ) ?;
541+ let h3_index_a = point_a. to_cell ( resolution) ;
542+
543+ for ( radius_meters, lat, lon) in estimates {
544+ let lat_f64 = lat
545+ . to_f64 ( )
546+ . ok_or_else ( || anyhow:: anyhow!( "Failed to convert lat_b to f64" ) ) ?;
547+ let lon_f64 = lon
548+ . to_f64 ( )
549+ . ok_or_else ( || anyhow:: anyhow!( "Failed to convert lon_b to f64" ) ) ?;
550+ let radius_meters_f64 = radius_meters
551+ . to_f64 ( )
552+ . ok_or_else ( || anyhow:: anyhow!( "Failed to convert radius_meters to f64" ) ) ?;
553+
554+ let point_b = LatLng :: new ( lat_f64, lon_f64)
555+ . map_err ( |e| anyhow:: anyhow!( "Invalid LatLng for B: {}" , e) ) ?;
556+ let h3_index_b = point_b. to_cell ( resolution) ;
557+
558+ let grid_distance = h3_index_a
559+ . grid_distance ( h3_index_b)
560+ . map_err ( |e| anyhow:: anyhow!( "Failed to calculate grid distance: {}" , e) ) ?;
561+
562+ let max_grid_distance = ( radius_meters_f64 / 9.0 ) . round ( ) as i32 ;
563+
564+ if grid_distance <= max_grid_distance {
565+ return Ok ( true ) ;
566+ }
567+ }
568+
569+ Ok ( false )
570+ }
571+
504572pub async fn reward_dc (
505573 mobile_rewards : & FileSinkClient < proto:: MobileRewardShare > ,
506574 reward_period : & Range < DateTime < Utc > > ,
0 commit comments