Skip to content

Commit

Permalink
Merge pull request #784 from helium/andymck/one-beacon-attempt-per-wi…
Browse files Browse the repository at this point in the history
…ndow

track last beacon ts for schedule and recip separately. ensure only one beacon attempt per beaconing window
  • Loading branch information
andymck authored Apr 9, 2024
2 parents 3d22551 + e0c928f commit cbd5850
Show file tree
Hide file tree
Showing 8 changed files with 570 additions and 87 deletions.
8 changes: 8 additions & 0 deletions iot_verifier/migrations/15_last_beacon_reciprocity.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
create table last_beacon_recip (
id bytea primary key not null,
timestamp timestamptz not null
);
-- seed beacon_recip with timestamps from last_beacon
insert into last_beacon_recip (id, timestamp)
select id, timestamp from last_beacon
where timestamp > now() - interval '7 day';
13 changes: 5 additions & 8 deletions iot_verifier/src/last_beacon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use chrono::{DateTime, Utc};
use helium_crypto::PublicKeyBinary;
use serde::{Deserialize, Serialize};
use sqlx::{postgres::PgRow, FromRow, Row};
use sqlx::{postgres::PgRow, FromRow, Postgres, Row, Transaction};

#[derive(Deserialize, Serialize, Debug)]
pub struct LastBeacon {
Expand Down Expand Up @@ -86,14 +86,11 @@ impl LastBeacon {
Ok(height)
}

pub async fn update_last_timestamp<'c, E>(
executor: E,
pub async fn update_last_timestamp(
txn: &mut Transaction<'_, Postgres>,
id: &PublicKeyBinary,
timestamp: DateTime<Utc>,
) -> anyhow::Result<()>
where
E: sqlx::Executor<'c, Database = sqlx::Postgres>,
{
) -> anyhow::Result<()> {
let _ = sqlx::query(
r#"
insert into last_beacon (id, timestamp)
Expand All @@ -104,7 +101,7 @@ impl LastBeacon {
)
.bind(id.as_ref())
.bind(timestamp)
.execute(executor)
.execute(txn)
.await?;
Ok(())
}
Expand Down
53 changes: 53 additions & 0 deletions iot_verifier/src/last_beacon_reciprocity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use chrono::{DateTime, Utc};
use helium_crypto::PublicKeyBinary;
use serde::{Deserialize, Serialize};
use sqlx::{postgres::PgRow, FromRow, Postgres, Row, Transaction};

#[derive(Deserialize, Serialize, Debug)]
pub struct LastBeaconReciprocity {
pub id: PublicKeyBinary,
pub timestamp: DateTime<Utc>,
}

impl FromRow<'_, PgRow> for LastBeaconReciprocity {
fn from_row(row: &PgRow) -> sqlx::Result<Self> {
Ok(Self {
id: row.get::<Vec<u8>, &str>("id").into(),
timestamp: row.get::<DateTime<Utc>, &str>("timestamp"),
})
}
}

impl LastBeaconReciprocity {
pub async fn get<'c, E>(executor: E, id: &PublicKeyBinary) -> anyhow::Result<Option<Self>>
where
E: sqlx::Executor<'c, Database = Postgres>,
{
Ok(sqlx::query_as::<_, LastBeaconReciprocity>(
r#" select * from last_beacon_recip where id = $1;"#,
)
.bind(id.as_ref())
.fetch_optional(executor)
.await?)
}

pub async fn update_last_timestamp(
txn: &mut Transaction<'_, Postgres>,
id: &PublicKeyBinary,
timestamp: DateTime<Utc>,
) -> anyhow::Result<()> {
let _ = sqlx::query(
r#"
insert into last_beacon_recip (id, timestamp)
values ($1, $2)
on conflict (id) do update set
timestamp = EXCLUDED.timestamp
"#,
)
.bind(id.as_ref())
.bind(timestamp)
.execute(txn)
.await?;
Ok(())
}
}
1 change: 1 addition & 0 deletions iot_verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod gateway_cache;
pub mod gateway_updater;
pub mod hex_density;
pub mod last_beacon;
pub mod last_beacon_reciprocity;
pub mod last_witness;
pub mod loader;
pub mod meta;
Expand Down
40 changes: 26 additions & 14 deletions iot_verifier/src/poc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
gateway_cache::{GatewayCache, GatewayCacheError},
hex_density::HexDensityMap,
last_beacon::LastBeacon,
last_beacon_reciprocity::LastBeaconReciprocity,
last_witness::LastWitness,
region_cache::RegionCache,
witness_updater::WitnessUpdater,
Expand Down Expand Up @@ -148,7 +149,7 @@ impl Poc {
};
// we have beaconer info, proceed to verifications
let last_beacon = LastBeacon::get(&self.pool, &beaconer_pub_key).await?;
match do_beacon_verifications(
let result = match do_beacon_verifications(
deny_list,
self.entropy_start,
self.entropy_end,
Expand All @@ -164,24 +165,35 @@ impl Poc {
.get(beaconer_metadata.location)
.await
.unwrap_or(*DEFAULT_TX_SCALE);
// update 'last beacon' timestamp if the beacon has passed regular validations
// but only if there has been at least one witness report
if !self.witness_reports.is_empty() {
LastBeacon::update_last_timestamp(
&self.pool,
&beaconer_pub_key,
self.beacon_report.received_timestamp,
)
.await?
}
Ok(VerifyBeaconResult::valid(beaconer_info, tx_scale))
VerifyBeaconResult::valid(beaconer_info, tx_scale)
}
Err(invalid_response) => Ok(VerifyBeaconResult::invalid(
Err(invalid_response) => VerifyBeaconResult::invalid(
invalid_response.reason,
invalid_response.details,
beaconer_info,
)),
),
};
let mut txn = self.pool.begin().await?;
// update 'last beacon' timestamp irrespective of whether the beacon is valid or not
LastBeacon::update_last_timestamp(
&mut txn,
&beaconer_pub_key,
self.beacon_report.received_timestamp,
)
.await?;
// update 'last beacon reciprocity' timestamp if the beacon has passed regular validations
// and has at least one witness report
if result.result == VerificationStatus::Valid && !self.witness_reports.is_empty() {
LastBeaconReciprocity::update_last_timestamp(
&mut txn,
&beaconer_pub_key,
self.beacon_report.received_timestamp,
)
.await?
}
txn.commit().await?;

Ok(result)
}

pub async fn verify_witnesses(
Expand Down
7 changes: 4 additions & 3 deletions iot_verifier/src/runner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
gateway_cache::GatewayCache,
hex_density::HexDensityMap,
last_beacon::LastBeacon,
last_beacon_reciprocity::LastBeaconReciprocity,
poc::{Poc, VerifyBeaconResult},
poc_report::Report,
region_cache::RegionCache,
Expand Down Expand Up @@ -567,8 +567,9 @@ where
&self,
report: &IotVerifiedWitnessReport,
) -> anyhow::Result<bool> {
let last_beacon = LastBeacon::get(&self.pool, &report.report.pub_key).await?;
Ok(last_beacon.map_or(false, |lw| {
let last_beacon_recip =
LastBeaconReciprocity::get(&self.pool, &report.report.pub_key).await?;
Ok(last_beacon_recip.map_or(false, |lw| {
report.received_timestamp - lw.timestamp < *RECIPROCITY_WINDOW
}))
}
Expand Down
4 changes: 2 additions & 2 deletions iot_verifier/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use iot_config::{
};
use iot_verifier::{
entropy::Entropy,
last_beacon::LastBeacon,
last_beacon_reciprocity::LastBeaconReciprocity,
last_witness::LastWitness,
poc_report::{InsertBindings, IotStatus, Report, ReportType},
};
Expand Down Expand Up @@ -311,7 +311,7 @@ pub async fn inject_last_beacon(
gateway: PublicKeyBinary,
ts: DateTime<Utc>,
) -> anyhow::Result<()> {
LastBeacon::update_last_timestamp(&mut *txn, &gateway, ts).await
LastBeaconReciprocity::update_last_timestamp(&mut *txn, &gateway, ts).await
}

#[allow(dead_code)]
Expand Down
Loading

0 comments on commit cbd5850

Please sign in to comment.