From 1abf20305a152ddd18396dc68fcaa520a03e4f90 Mon Sep 17 00:00:00 2001 From: Michael Jeffrey Date: Tue, 1 Oct 2024 10:01:21 -0700 Subject: [PATCH] Service Providers can use multiple keys for dc_transfer For accounting reasons, Service Providers can have multiple payer keys listed. We need to ensuure all their dc transfer are accumulated into their service provider entry when we are generating rewards. --- .../src/service_provider/dc_sessions.rs | 76 +++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/mobile_verifier/src/service_provider/dc_sessions.rs b/mobile_verifier/src/service_provider/dc_sessions.rs index 68917ef09..1888c3bfa 100644 --- a/mobile_verifier/src/service_provider/dc_sessions.rs +++ b/mobile_verifier/src/service_provider/dc_sessions.rs @@ -39,7 +39,7 @@ pub struct ServiceProviderDCSessions(pub(crate) HashMap Decimal { @@ -94,11 +94,77 @@ where I: Into, { fn from(iter: F) -> Self { - // sum duplicate keys - let mut map = HashMap::new(); + let mut me = Self::default(); for (k, v) in iter { - *map.entry(k.into()).or_insert(Decimal::ZERO) += v; + me.insert(k.into(), v); } - Self(map) + me + } +} + +#[cfg(test)] +pub mod tests { + + use chrono::Duration; + use helium_proto::ServiceProvider; + + use crate::data_session::HotspotDataSession; + + use super::*; + + impl ServiceProviderDCSessions { + fn len(&self) -> usize { + self.0.len() + } + } + + #[sqlx::test] + fn multiple_payer_keys_accumulate_to_service_provider(pool: PgPool) -> anyhow::Result<()> { + // Client always resolves to single service provider no matter payer key + struct MockClient; + + #[async_trait::async_trait] + impl CarrierServiceVerifier for MockClient { + type Error = ClientError; + + async fn payer_key_to_service_provider<'a>( + &self, + _pubkey: &str, + ) -> Result { + Ok(ServiceProvider::HeliumMobile) + } + } + + // Save multiple data sessions with different payers + let one = HotspotDataSession { + pub_key: vec![0].into(), + payer: vec![0].into(), + upload_bytes: 1_000, + download_bytes: 1_000, + num_dcs: 2_000, + received_timestamp: Utc::now(), + }; + let two = HotspotDataSession { + pub_key: vec![1].into(), + payer: vec![1].into(), + upload_bytes: 1_000, + download_bytes: 1_000, + num_dcs: 2_000, + received_timestamp: Utc::now(), + }; + let mut txn = pool.begin().await?; + one.save(&mut txn).await?; + two.save(&mut txn).await?; + txn.commit().await?; + + let now = Utc::now(); + let epoch = now - Duration::hours(24)..now; + + // dc sessions should represent single payer, and all dc is combined + let map = fetch_dc_sessions(&pool, &MockClient, &epoch).await?; + assert_eq!(map.len(), 1); + assert_eq!(map.all_transfer(), Decimal::from(4_000)); + + Ok(()) } }