From 991ebea3efe52373a6826ba456f2e66f3dadbdcc Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 19 Nov 2024 13:14:00 +0000 Subject: [PATCH 01/36] initial implementation of changes to support hip138 in mobile verifier --- Cargo.lock | 5 +- Cargo.toml | 10 +- file_store/src/traits/msg_verify.rs | 2 + iot_verifier/src/rewarder.rs | 21 +- mobile_config/Cargo.toml | 2 + mobile_config/src/client/mod.rs | 4 + mobile_config/src/client/settings.rs | 5 + mobile_config/src/client/sub_dao_client.rs | 75 +++++ mobile_config/src/lib.rs | 25 ++ .../src/sub_dao_epoch_reward_info.rs | 108 ++++++ mobile_config/src/sub_dao_service.rs | 97 ++++++ mobile_config/src/telemetry.rs | 6 + mobile_verifier/src/cli/reward_from_db.rs | 53 +-- mobile_verifier/src/cli/server.rs | 6 +- mobile_verifier/src/lib.rs | 2 + mobile_verifier/src/reward_shares.rs | 316 +++++++++--------- mobile_verifier/src/rewarder.rs | 244 +++++++------- .../src/service_provider/dc_sessions.rs | 4 +- mobile_verifier/src/service_provider/mod.rs | 32 +- .../src/service_provider/reward.rs | 95 +++--- mobile_verifier/src/telemetry.rs | 9 +- .../tests/integrations/common/mod.rs | 39 ++- .../tests/integrations/hex_boosting.rs | 192 ++++++----- .../tests/integrations/rewarder_mappers.rs | 38 +-- .../tests/integrations/rewarder_oracles.rs | 20 +- .../tests/integrations/rewarder_poc_dc.rs | 21 +- .../tests/integrations/rewarder_sp_rewards.rs | 67 ++-- .../subscriber_verified_mapping_event.rs | 2 +- reward_scheduler/src/lib.rs | 58 ++-- 29 files changed, 989 insertions(+), 569 deletions(-) create mode 100644 mobile_config/src/client/sub_dao_client.rs create mode 100644 mobile_config/src/sub_dao_epoch_reward_info.rs create mode 100644 mobile_config/src/sub_dao_service.rs diff --git a/Cargo.lock b/Cargo.lock index b03eaafaf..dbbeef562 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#4085e00c6f4d82c3da798ae1bc97324bc9cada2e" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" dependencies = [ "base64 0.21.7", "byteorder", @@ -3821,7 +3821,6 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#4085e00c6f4d82c3da798ae1bc97324bc9cada2e" dependencies = [ "bytes", "prost", @@ -5047,6 +5046,8 @@ dependencies = [ "prost", "rand 0.8.5", "retainer", + "rust_decimal", + "rust_decimal_macros", "serde", "serde_json", "solana-sdk", diff --git a/Cargo.toml b/Cargo.toml index 7388ff0ad..fae3f6697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,10 +70,10 @@ helium-lib = { git = "https://github.com/helium/helium-wallet-rs.git", branch = hextree = { git = "https://github.com/jaykickliter/HexTree", branch = "main", features = [ "disktree", ] } -helium-proto = { git = "https://github.com/helium/proto", branch = "master", features = [ +helium-proto = { git = "https://github.com/helium/proto", branch = "andymck/sub-dao-epoch-support", features = [ "services", ] } -beacon = { git = "https://github.com/helium/proto", branch = "master" } +beacon = { git = "https://github.com/helium/proto", branch = "andymck/sub-dao-epoch-support" } solana-client = "1.18" solana-sdk = "1.18" solana-program = "1.18" @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # -# [patch.'https://github.com/helium/proto'] -# helium-proto = { path = "../proto" } -# beacon = { path = "../proto/beacon" } + [patch.'https://github.com/helium/proto'] + helium-proto = { path = "../../proto" } +# beacon = { path = "../../proto" } diff --git a/file_store/src/traits/msg_verify.rs b/file_store/src/traits/msg_verify.rs index 6f88c0ab6..a8401cb36 100644 --- a/file_store/src/traits/msg_verify.rs +++ b/file_store/src/traits/msg_verify.rs @@ -98,6 +98,8 @@ impl_msg_verify!(mobile_config::GatewayInfoStreamResV2, signature); impl_msg_verify!(mobile_config::BoostedHexInfoStreamReqV1, signature); impl_msg_verify!(mobile_config::BoostedHexModifiedInfoStreamReqV1, signature); impl_msg_verify!(mobile_config::BoostedHexInfoStreamResV1, signature); +impl_msg_verify!(mobile_config::SubDaoEpochRewardInfoReqV1, signature); +impl_msg_verify!(mobile_config::SubDaoEpochRewardInfoResV1, signature); impl_msg_verify!(poc_mobile::SubscriberVerifiedMappingEventReqV1, signature); impl_msg_verify!(poc_mobile::HexUsageStatsReqV1, signature); impl_msg_verify!(poc_mobile::RadioUsageStatsReqV1, signature); diff --git a/iot_verifier/src/rewarder.rs b/iot_verifier/src/rewarder.rs index 1f9bd1527..570653e2f 100644 --- a/iot_verifier/src/rewarder.rs +++ b/iot_verifier/src/rewarder.rs @@ -84,16 +84,16 @@ impl Rewarder { self.reward_offset, ); - let sleep_duration = if scheduler.should_reward(now) { + let sleep_duration = if scheduler.should_trigger(now) { let iot_price = self .price_tracker .price(&helium_proto::BlockchainTokenTypeV1::Iot) .await?; tracing::info!( "Rewarding for period: {:?} with iot_price: {iot_price}", - scheduler.reward_period + scheduler.schedule_period ); - if self.data_current_check(&scheduler.reward_period).await? { + if self.data_current_check(&scheduler.schedule_period).await? { self.reward(&scheduler, Decimal::from(iot_price)).await?; scheduler.sleep_duration(Utc::now())? } else { @@ -123,7 +123,7 @@ impl Rewarder { scheduler: &Scheduler, iot_price: Decimal, ) -> anyhow::Result<()> { - let reward_period = &scheduler.reward_period; + let reward_period = &scheduler.schedule_period; // process rewards for poc and dc let poc_dc_shares = @@ -139,17 +139,17 @@ impl Rewarder { // purge db let mut transaction = self.pool.begin().await?; // Clear gateway shares table period to end of reward period - GatewayShares::clear_rewarded_shares(&mut transaction, scheduler.reward_period.start) + GatewayShares::clear_rewarded_shares(&mut transaction, scheduler.schedule_period.start) .await?; save_rewarded_timestamp( "last_rewarded_end_time", - &scheduler.reward_period.end, + &scheduler.schedule_period.end, &mut transaction, ) .await?; save_rewarded_timestamp( "next_rewarded_end_time", - &scheduler.next_reward_period().end, + &scheduler.next_trigger_period().end, &mut transaction, ) .await?; @@ -170,17 +170,18 @@ impl Rewarder { self.reward_manifests_sink .write( RewardManifest { - start_timestamp: scheduler.reward_period.start.encode_timestamp(), - end_timestamp: scheduler.reward_period.end.encode_timestamp(), + start_timestamp: scheduler.schedule_period.start.encode_timestamp(), + end_timestamp: scheduler.schedule_period.end.encode_timestamp(), written_files, reward_data: Some(IotRewardData(reward_data)), + epoch: 0, // TODO: replace placeholder value }, [], ) .await? .await??; self.reward_manifests_sink.commit().await?; - telemetry::last_rewarded_end_time(scheduler.reward_period.end); + telemetry::last_rewarded_end_time(scheduler.schedule_period.end); Ok(()) } diff --git a/mobile_config/Cargo.toml b/mobile_config/Cargo.toml index 74479694b..ae323e008 100644 --- a/mobile_config/Cargo.toml +++ b/mobile_config/Cargo.toml @@ -16,6 +16,8 @@ chrono = { workspace = true } clap = { workspace = true } config = { workspace = true } db-store = { path = "../db_store" } +rust_decimal = { workspace = true } +rust_decimal_macros = { workspace = true } file-store = { path = "../file_store" } futures = { workspace = true } futures-util = { workspace = true } diff --git a/mobile_config/src/client/mod.rs b/mobile_config/src/client/mod.rs index 723bdda42..1c3f3587d 100644 --- a/mobile_config/src/client/mod.rs +++ b/mobile_config/src/client/mod.rs @@ -4,6 +4,7 @@ pub mod entity_client; pub mod gateway_client; pub mod hex_boosting_client; mod settings; +pub mod sub_dao_client; use std::time::Duration; @@ -12,6 +13,7 @@ pub use carrier_service_client::CarrierServiceClient; pub use entity_client::EntityClient; pub use gateway_client::GatewayClient; pub use settings::Settings; +pub use sub_dao_client::SubDaoClient; const CACHE_EVICTION_FREQUENCY: Duration = Duration::from_secs(60 * 60); @@ -29,6 +31,8 @@ pub enum ClientError { UnknownServiceProvider(String), #[error("Invalid GatewayInfo proto response {0}")] InvalidGatewayInfoProto(#[from] crate::gateway_info::GatewayInfoProtoParseError), + #[error("error {0}")] + AnyhowError(#[from] anyhow::Error), } macro_rules! call_with_retry { diff --git a/mobile_config/src/client/settings.rs b/mobile_config/src/client/settings.rs index 902381fd3..79a2132ce 100644 --- a/mobile_config/src/client/settings.rs +++ b/mobile_config/src/client/settings.rs @@ -49,6 +49,11 @@ fn default_cache_ttl_in_secs() -> Duration { } impl Settings { + pub fn connect_epoch_client(&self) -> mobile_config::sub_dao_client::SubDaoClient { + let channel = connect_channel(self); + mobile_config::sub_dao_client::SubDaoClient::new(channel) + } + pub fn connect_gateway_client(&self) -> mobile_config::GatewayClient { let channel = connect_channel(self); mobile_config::GatewayClient::new(channel) diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs new file mode 100644 index 000000000..7606c7ffa --- /dev/null +++ b/mobile_config/src/client/sub_dao_client.rs @@ -0,0 +1,75 @@ +use super::{call_with_retry, ClientError, Settings}; +use crate::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; +use file_store::traits::MsgVerify; +use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; +use helium_proto::services::mobile_config::SubDaoEpochRewardInfoReqV1; +use helium_proto::{ + services::{mobile_config, Channel}, + Message, +}; +use std::{error::Error, sync::Arc, time::Duration}; + +#[derive(Clone)] +pub struct SubDaoClient { + pub client: mobile_config::sub_dao_client::SubDaoClient, + signing_key: Arc, + config_pubkey: PublicKey, +} + +impl SubDaoClient { + pub fn from_settings(settings: &Settings) -> Result> { + Ok(Self { + client: settings.connect_epoch_client(), + signing_key: settings.signing_keypair()?, + config_pubkey: settings.config_pubkey()?, + }) + } +} + +#[async_trait::async_trait] +pub trait SubDaoEpochRewardInfoResolver: Clone + Send + Sync + 'static { + type Error: Error + Send + Sync + 'static; + + async fn resolve_info( + &self, + sub_dao: &PublicKeyBinary, + epoch: u64, + ) -> Result, Self::Error>; +} + +#[async_trait::async_trait] +impl SubDaoEpochRewardInfoResolver for SubDaoClient { + type Error = ClientError; + + async fn resolve_info( + &self, + sub_dao: &PublicKeyBinary, + epoch: u64, + ) -> Result, Self::Error> { + let mut request = SubDaoEpochRewardInfoReqV1 { + sub_dao: sub_dao.clone().into(), + epoch, + signer: self.signing_key.public_key().into(), + signature: vec![], + }; + request.signature = self.signing_key.sign(&request.encode_to_vec())?; + tracing::debug!( + subdao = sub_dao.to_string(), + epoch = epoch, + "fetching subdao epoch info" + ); + let response = match call_with_retry!(self.client.clone().info(request.clone())) { + Ok(info_res) => { + let response = info_res.into_inner(); + response.verify(&self.config_pubkey)?; + response + .info + .map(ResolvedSubDaoEpochRewardInfo::try_from) + .transpose()? + } + Err(status) if status.code() == tonic::Code::NotFound => None, + Err(status) => Err(status)?, + }; + Ok(response) + } +} diff --git a/mobile_config/src/lib.rs b/mobile_config/src/lib.rs index 964086a14..c41c0342b 100644 --- a/mobile_config/src/lib.rs +++ b/mobile_config/src/lib.rs @@ -1,6 +1,9 @@ +use anyhow::anyhow; +use chrono::{DateTime, Duration, TimeZone, Utc}; use helium_crypto::PublicKey; use helium_proto::services::mobile_config::AdminKeyRole as ProtoKeyRole; use serde::Serialize; +use std::ops::Range; use tokio_stream::wrappers::ReceiverStream; use tonic::{Response, Status}; @@ -13,10 +16,12 @@ pub mod entity_service; pub mod gateway_info; pub mod gateway_service; pub mod hex_boosting_service; +pub mod sub_dao_epoch_reward_info; pub mod key_cache; pub mod mobile_radio_tracker; pub mod settings; +pub mod sub_dao_service; pub mod telemetry; pub use client::{GatewayClient, Settings as ClientSettings}; @@ -94,3 +99,23 @@ impl std::fmt::Display for KeyRole { f.write_str(s) } } + +pub struct EpochPeriod { + pub period: Range>, +} + +impl TryFrom for EpochPeriod { + type Error = anyhow::Error; + + fn try_from(next_reward_epoch: u64) -> anyhow::Result { + let start_time = Utc + .timestamp_opt(0, 0) + .single() + .ok_or_else(|| anyhow!("Failed to get Unix epoch start time"))? + + Duration::days(next_reward_epoch as i64); + let end_time = start_time + Duration::days(1); + Ok(EpochPeriod { + period: start_time..end_time, + }) + } +} diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs new file mode 100644 index 000000000..e9b6e3460 --- /dev/null +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -0,0 +1,108 @@ +use crate::EpochPeriod; +use chrono::{DateTime, Utc}; +use file_store::traits::{TimestampDecode, TimestampEncode}; +use helium_crypto::PublicKeyBinary; +use helium_proto::services::mobile_config::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; +use rust_decimal::prelude::*; +use sqlx::FromRow; +use std::ops::Range; + +#[derive(Clone, Debug)] +pub struct ResolvedSubDaoEpochRewardInfo { + pub epoch: u64, + pub epoch_address: PublicKeyBinary, + pub sub_dao_address: PublicKeyBinary, + pub epoch_period: Range>, + pub epoch_emissions: Decimal, + pub rewards_issued_at: DateTime, +} + +#[derive(Clone, Debug, FromRow)] +pub struct RawSubDaoEpochRewardInfo { + #[sqlx(try_from = "i64")] + pub epoch: u64, + pub epoch_address: PublicKeyBinary, + pub sub_dao_address: PublicKeyBinary, + #[sqlx(try_from = "i64")] + pub sub_dao_utility_score: u64, + #[sqlx(try_from = "i64")] + pub total_utility_score: u64, + #[sqlx(try_from = "i64")] + pub total_emissions: u64, + pub rewards_issued_at: DateTime, +} + +// server goes from raw to proto, client goes from proto to resolved +impl TryFrom for SubDaoEpochRewardInfoProto { + type Error = anyhow::Error; + + fn try_from(info: RawSubDaoEpochRewardInfo) -> Result { + Ok(Self { + epoch: info.epoch, + address: info.epoch_address.into(), + sub_dao: info.sub_dao_address.into(), + sub_dao_utility_score: info.sub_dao_utility_score, + total_utility_score: info.total_utility_score, + total_emissions: info.total_emissions, + rewards_issued_at: info.rewards_issued_at.encode_timestamp(), + }) + } +} + +// server returns the proto struct to client, client resolves to the resolved struct +impl TryFrom for ResolvedSubDaoEpochRewardInfo { + type Error = anyhow::Error; + + fn try_from(info: SubDaoEpochRewardInfoProto) -> Result { + let epoch_period: EpochPeriod = info.epoch.try_into()?; + // todo: confirm rounding requirements here + let epoch_rewards = Decimal::from( + info.total_emissions * (info.sub_dao_utility_score / info.total_utility_score), + ); + + Ok(Self { + epoch: info.epoch, + epoch_address: info.address.into(), + sub_dao_address: info.sub_dao.into(), + epoch_period: epoch_period.period, + epoch_emissions: epoch_rewards, + rewards_issued_at: info.rewards_issued_at.to_timestamp()?, + }) + } +} + +pub(crate) mod db { + + use crate::sub_dao_epoch_reward_info::RawSubDaoEpochRewardInfo; + use helium_crypto::PublicKeyBinary; + use sqlx::PgExecutor; + + const GET_EPOCH_REWARD_INFO_SQL: &str = r#" + SELECT + t_subdao.address AS epoch_address, + t_subdao.sub_dao AS sub_dao_address, + t_subdao.epoch, + t_subdao.utility_score, + t_dao.total_utility_score, + t_dao.total_rewards, + t_subdao.rewards_issued_at + FROM sub_dao_epoch_infos t_subdao + JOIN dao_epoch_infos t_dao ON t_subdao.epoch = t_dao.epoch + WHERE t_subdao.epoch = $1 AND t_subdao.sub_dao = $2 + "#; + + pub async fn get_info( + db: impl PgExecutor<'_>, + epoch: u64, + sub_dao: PublicKeyBinary, + ) -> anyhow::Result> { + let mut query: sqlx::QueryBuilder = + sqlx::QueryBuilder::new(GET_EPOCH_REWARD_INFO_SQL); + Ok(query + .build_query_as::() + .bind(epoch as i64) + .bind(sub_dao.to_string()) + .fetch_optional(db) + .await?) + } +} diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs new file mode 100644 index 000000000..5c46cd97e --- /dev/null +++ b/mobile_config/src/sub_dao_service.rs @@ -0,0 +1,97 @@ +use crate::{ + key_cache::KeyCache, sub_dao_epoch_reward_info, telemetry, verify_public_key, GrpcResult, +}; +use chrono::Utc; +use file_store::traits::{MsgVerify, TimestampEncode}; +use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; +use helium_proto::{ + services::mobile_config::{self, SubDaoEpochRewardInfoReqV1, SubDaoEpochRewardInfoResV1}, + Message, +}; +use sqlx::{Pool, Postgres}; +use std::sync::Arc; +use tonic::{Request, Response, Status}; + +pub struct SuDaoService { + key_cache: KeyCache, + metadata_pool: Pool, + signing_key: Arc, +} + +impl SuDaoService { + pub fn new(key_cache: KeyCache, metadata_pool: Pool, signing_key: Keypair) -> Self { + Self { + key_cache, + metadata_pool, + signing_key: Arc::new(signing_key), + } + } + + fn verify_request_signature(&self, signer: &PublicKey, request: &R) -> Result<(), Status> + where + R: MsgVerify, + { + if self.key_cache.verify_signature(signer, request).is_ok() { + tracing::debug!(signer = signer.to_string(), "request authorized"); + return Ok(()); + } + Err(Status::permission_denied("unauthorized request signature")) + } + + fn verify_request_signature_for_info( + &self, + request: &SubDaoEpochRewardInfoReqV1, + ) -> Result<(), Status> { + let signer = verify_public_key(&request.signer)?; + self.verify_request_signature(&signer, request) + } + + fn sign_response(&self, response: &[u8]) -> Result, Status> { + self.signing_key + .sign(response) + .map_err(|_| Status::internal("response signing error")) + } +} + +#[tonic::async_trait] +impl mobile_config::sub_dao_server::SubDao for SuDaoService { + async fn info( + &self, + request: Request, + ) -> GrpcResult { + let request = request.into_inner(); + telemetry::count_request("sub_dao_reward_info", "info"); + custom_tracing::record_b58("sub_dao", &request.sub_dao); + custom_tracing::record("epoch", request.epoch); + custom_tracing::record_b58("signer", &request.signer); + + self.verify_request_signature_for_info(&request)?; + + let epoch = request.epoch; + let sub_dao: PublicKeyBinary = request.sub_dao.into(); + tracing::debug!(sub_dao = %sub_dao, epoch = epoch, "fetching sub_dao epoch reward info"); + + sub_dao_epoch_reward_info::db::get_info(&self.metadata_pool, epoch, sub_dao) + .await + .map_err(|_| Status::internal("error fetching sub_dao epoch reward info"))? + .map_or_else( + || { + telemetry::count_epoch_chain_lookup("not-found"); + Err(Status::not_found(epoch.to_string())) + }, + |info| { + let info = info.try_into().map_err(|_| { + Status::internal("error serializing sub_dao epoch reward info") + })?; + let mut res = SubDaoEpochRewardInfoResV1 { + info: Some(info), + timestamp: Utc::now().encode_timestamp(), + signer: self.signing_key.public_key().into(), + signature: vec![], + }; + res.signature = self.sign_response(&res.encode_to_vec())?; + Ok(Response::new(res)) + }, + ) + } +} diff --git a/mobile_config/src/telemetry.rs b/mobile_config/src/telemetry.rs index 550b2df21..2552ee802 100644 --- a/mobile_config/src/telemetry.rs +++ b/mobile_config/src/telemetry.rs @@ -2,6 +2,8 @@ const RPC_METRIC: &str = concat!(env!("CARGO_PKG_NAME"), "-", "grpc-request"); const GATEWAY_CHAIN_LOOKUP_METRIC: &str = concat!(env!("CARGO_PKG_NAME"), "-", "gateway-chain-lookup"); +const EPOCH_CHAIN_LOOKUP_METRIC: &str = concat!(env!("CARGO_PKG_NAME"), "-", "epoch-chain-lookup"); + pub fn count_request(service: &'static str, rpc: &'static str) { metrics::counter!(RPC_METRIC, "service" => service, "rpc" => rpc).increment(1); } @@ -9,3 +11,7 @@ pub fn count_request(service: &'static str, rpc: &'static str) { pub fn count_gateway_chain_lookup(result: &'static str) { metrics::counter!(GATEWAY_CHAIN_LOOKUP_METRIC, "result" => result).increment(1); } + +pub fn count_epoch_chain_lookup(result: &'static str) { + metrics::counter!(EPOCH_CHAIN_LOOKUP_METRIC, "result" => result).increment(1); +} diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index b669b4409..6dbb69256 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -6,42 +6,55 @@ use crate::{ rewarder::boosted_hex_eligibility::BoostedHexEligibility, sp_boosted_rewards_bans::BannedRadios, speedtests_average::SpeedtestAverages, - unique_connections, Settings, + unique_connections, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, }; use anyhow::Result; -use chrono::NaiveDateTime; -use helium_crypto::PublicKey; +use helium_crypto::{PublicKey, PublicKeyBinary}; use helium_proto::services::poc_mobile as proto; -use mobile_config::boosted_hex_info::BoostedHexes; +use mobile_config::{ + boosted_hex_info::BoostedHexes, + client::{sub_dao_client::SubDaoEpochRewardInfoResolver, SubDaoClient}, +}; use serde_json::json; -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; -/// Reward a period from the entries in the database +/// Reward an epoch from the entries in the database #[derive(Debug, clap::Args)] pub struct Cmd { #[clap(long)] - start: NaiveDateTime, - #[clap(long)] - end: NaiveDateTime, + reward_epoch: u64, } impl Cmd { pub async fn run(self, settings: &Settings) -> Result<()> { - let Self { start, end } = self; + // TODO: do we want to continue maintaining this cli ? - let start = start.and_utc(); - let end = end.and_utc(); + let reward_epoch = self.reward_epoch; - tracing::info!("Rewarding shares from the following time range: {start} to {end}"); - let epoch = start..end; - let expected_rewards = get_scheduled_tokens_for_poc(epoch.end - epoch.start); + let sub_dao_pubkey = PublicKeyBinary::from_str(&MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; + let sub_dao_rewards_client = SubDaoClient::from_settings(&settings.config_client)?; + let reward_info = sub_dao_rewards_client + .resolve_info(&sub_dao_pubkey, reward_epoch) + .await? + .ok_or(anyhow::anyhow!( + "No reward info found for epoch {}", + reward_epoch + ))?; + + tracing::info!( + "Rewarding shares from the following time range: {} to {}", + reward_info.epoch_period.start, + reward_info.epoch_period.end + ); + let expected_rewards = get_scheduled_tokens_for_poc(reward_info.epoch_emissions); let (shutdown_trigger, _shutdown_listener) = triggered::trigger(); let pool = settings.database.connect(env!("CARGO_PKG_NAME")).await?; - let heartbeats = HeartbeatReward::validated(&pool, &epoch); + let heartbeats = HeartbeatReward::validated(&pool, &reward_info.epoch_period); let speedtest_averages = - SpeedtestAverages::aggregate_epoch_averages(epoch.end, &pool).await?; + SpeedtestAverages::aggregate_epoch_averages(reward_info.epoch_period.end, &pool) + .await?; let unique_connections = unique_connections::db::get(&pool, &epoch).await?; @@ -53,7 +66,7 @@ impl Cmd { &BoostedHexEligibility::default(), &BannedRadios::default(), &unique_connections, - &epoch, + &reward_info.epoch_period, ) .await?; @@ -61,8 +74,8 @@ impl Cmd { let mut owner_rewards = HashMap::<_, u64>::new(); let radio_rewards = reward_shares .into_rewards( - DataTransferAndPocAllocatedRewardBuckets::new(&epoch), - &epoch, + DataTransferAndPocAllocatedRewardBuckets::new(reward_info.epoch_emissions), + &reward_info, ) .ok_or(anyhow::anyhow!("no rewardable events"))? .1; diff --git a/mobile_verifier/src/cli/server.rs b/mobile_verifier/src/cli/server.rs index 539f0eb16..eb261aa81 100644 --- a/mobile_verifier/src/cli/server.rs +++ b/mobile_verifier/src/cli/server.rs @@ -24,8 +24,8 @@ use file_store::{ }; use helium_proto::services::poc_mobile::{Heartbeat, SeniorityUpdate, SpeedtestAvg}; use mobile_config::client::{ - entity_client::EntityClient, hex_boosting_client::HexBoostingClient, AuthorizationClient, - CarrierServiceClient, GatewayClient, + entity_client::EntityClient, hex_boosting_client::HexBoostingClient, + sub_dao_client::SubDaoClient, AuthorizationClient, CarrierServiceClient, GatewayClient, }; use task_manager::TaskManager; @@ -54,6 +54,7 @@ impl Cmd { let entity_client = EntityClient::from_settings(&settings.config_client)?; let carrier_client = CarrierServiceClient::from_settings(&settings.config_client)?; let hex_boosting_client = HexBoostingClient::from_settings(&settings.config_client)?; + let sub_dao_rewards_client = SubDaoClient::from_settings(&settings.config_client)?; let (valid_heartbeats, valid_heartbeats_server) = Heartbeat::file_sink( store_base_path, @@ -224,6 +225,7 @@ impl Cmd { file_upload, carrier_client, hex_boosting_client, + sub_dao_rewards_client, speedtests_avg, ) .await?, diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index d14bf4ee3..17ad5d268 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -24,6 +24,8 @@ pub use settings::Settings; use async_trait::async_trait; use std::error::Error; +pub const MOBILE_SUB_DAO_ONCHAIN_ADDRESS: &str = "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk"; + pub enum GatewayResolution { GatewayNotFound, GatewayNotAsserted, diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 63cb7fffe..474157e7a 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -21,7 +21,9 @@ use helium_crypto::PublicKeyBinary; use helium_proto::services::{ poc_mobile as proto, poc_mobile::mobile_reward_share::Reward as ProtoReward, }; -use mobile_config::boosted_hex_info::BoostedHexes; +use mobile_config::{ + boosted_hex_info::BoostedHexes, sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo, +}; use radio_reward_v2::{RadioRewardV2Ext, ToProtoDecimal}; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -30,9 +32,6 @@ use uuid::Uuid; mod radio_reward_v2; -/// Total tokens emissions pool per 365 days or 366 days for a leap year -const TOTAL_EMISSIONS_POOL: Decimal = dec!(30_000_000_000_000_000); - /// Maximum amount of the total emissions pool allocated for data transfer /// rewards const MAX_DATA_TRANSFER_REWARDS_PERCENT: Decimal = dec!(0.4); @@ -66,7 +65,7 @@ pub struct TransferRewards { reward_scale: Decimal, rewards: HashMap, reward_sum: Decimal, - mobile_bone_price: Decimal, + hnt_bone_price: Decimal, } #[derive(Copy, Clone, Debug)] @@ -102,7 +101,7 @@ impl TransferRewards { } pub async fn from_transfer_sessions( - mobile_bone_price: Decimal, + hnt_bone_price: Decimal, transfer_sessions: HotspotMap, reward_shares: &DataTransferAndPocAllocatedRewardBuckets, ) -> Self { @@ -112,7 +111,7 @@ impl TransferRewards { // Calculate rewards per hotspot .map(|(pub_key, rewardable)| { let bones = - dc_to_mobile_bones(Decimal::from(rewardable.rewardable_dc), mobile_bone_price); + dc_to_hnt_bones(Decimal::from(rewardable.rewardable_dc), hnt_bone_price); reward_sum += bones; ( pub_key, @@ -137,21 +136,21 @@ impl TransferRewards { reward_scale, rewards, reward_sum: reward_sum * reward_scale, - mobile_bone_price, + hnt_bone_price, } } pub fn into_rewards( self, - epoch: &'_ Range>, + reward_info: &'_ ResolvedSubDaoEpochRewardInfo, ) -> impl Iterator + '_ { let Self { reward_scale, rewards, .. } = self; - let start_period = epoch.start.encode_timestamp(); - let end_period = epoch.end.encode_timestamp(); + let start_period = reward_info.epoch_period.start.encode_timestamp(); + let end_period = reward_info.epoch_period.end.encode_timestamp(); rewards .into_iter() .map(move |(hotspot_key, reward)| { @@ -164,14 +163,17 @@ impl TransferRewards { proto::MobileRewardShare { start_period, end_period, + epoch: reward_info.epoch, reward: Some(proto::mobile_reward_share::Reward::GatewayReward( proto::GatewayReward { hotspot_key: hotspot_key.into(), dc_transfer_reward, rewardable_bytes: reward.bytes_rewarded, - price: (self.mobile_bone_price * dec!(1_000_000) * dec!(1_000_000)) - .to_u64() - .unwrap_or_default(), + price: (self.hnt_bone_price + * dec!(1_0000_0000) + * dec!(1_0000_0000)) + .to_u64() + .unwrap_or_default(), }, )), }, @@ -224,7 +226,7 @@ impl MapperShares { pub fn into_subscriber_rewards( self, - reward_period: &'_ Range>, + reward_info: &'_ ResolvedSubDaoEpochRewardInfo, reward_per_share: Decimal, ) -> impl Iterator + '_ { let mut subscriber_rewards: HashMap, proto::SubscriberReward> = HashMap::new(); @@ -285,8 +287,9 @@ impl MapperShares { ( total_reward_amount, proto::MobileRewardShare { - start_period: reward_period.start.encode_timestamp(), - end_period: reward_period.end.encode_timestamp(), + start_period: reward_info.epoch_period.start.encode_timestamp(), + end_period: reward_info.epoch_period.end.encode_timestamp(), + epoch: reward_info.epoch, reward: Some(ProtoReward::SubscriberReward(subscriber_reward)), }, ) @@ -294,16 +297,16 @@ impl MapperShares { } } -/// Returns the equivalent amount of Mobile bones for a specified amount of Data Credits -pub fn dc_to_mobile_bones(dc_amount: Decimal, mobile_bone_price: Decimal) -> Decimal { +/// Returns the equivalent amount of Hnt bones for a specified amount of Data Credits +pub fn dc_to_hnt_bones(dc_amount: Decimal, hnt_bone_price: Decimal) -> Decimal { let dc_in_usd = dc_amount * DC_USD_PRICE; - (dc_in_usd / mobile_bone_price) + (dc_in_usd / hnt_bone_price) .round_dp_with_strategy(DEFAULT_PREC, RoundingStrategy::ToPositiveInfinity) } pub fn coverage_point_to_mobile_reward_share( coverage_points: coverage_point_calculator::CoveragePoints, - reward_epoch: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, radio_id: &RadioId, poc_reward: u64, rewards_per_share: CalculatedPocRewardShares, @@ -370,8 +373,9 @@ pub fn coverage_point_to_mobile_reward_share( }); let base = proto::MobileRewardShare { - start_period: reward_epoch.start.encode_timestamp(), - end_period: reward_epoch.end.encode_timestamp(), + start_period: reward_info.epoch_period.start.encode_timestamp(), + end_period: reward_info.epoch_period.end.encode_timestamp(), + epoch: reward_info.epoch, reward: None, }; @@ -563,7 +567,7 @@ impl CoverageShares { pub fn into_rewards( self, reward_shares: DataTransferAndPocAllocatedRewardBuckets, - epoch: &'_ Range>, + reward_info: &'_ ResolvedSubDaoEpochRewardInfo, ) -> Option<( CalculatedPocRewardShares, impl Iterator + '_, @@ -601,7 +605,7 @@ impl CoverageShares { reward_shares, processed_radios.iter().map(|radio| &radio.points), ) else { - tracing::info!(?epoch, "could not calculate reward shares"); + tracing::info!(?reward_info.epoch_period, "could not calculate reward shares"); return None; }; @@ -621,7 +625,7 @@ impl CoverageShares { let (mobile_reward_v1, mobile_reward_v2) = coverage_point_to_mobile_reward_share( points, - epoch, + reward_info, &radio_id, poc_reward, rewards_per_share, @@ -650,10 +654,7 @@ pub struct DataTransferAndPocAllocatedRewardBuckets { } impl DataTransferAndPocAllocatedRewardBuckets { - pub fn new(epoch: &Range>) -> Self { - let duration = epoch.end - epoch.start; - let total_emission_pool = get_total_scheduled_tokens(duration); - + pub fn new(total_emission_pool: Decimal) -> Self { Self { data_transfer: total_emission_pool * MAX_DATA_TRANSFER_REWARDS_PERCENT, poc: total_emission_pool * POC_REWARDS_PERCENT, @@ -661,10 +662,7 @@ impl DataTransferAndPocAllocatedRewardBuckets { } } - pub fn new_poc_only(epoch: &Range>) -> Self { - let duration = epoch.end - epoch.start; - let total_emission_pool = get_total_scheduled_tokens(duration); - + pub fn new_poc_only(total_emission_pool: Decimal) -> Self { let poc = total_emission_pool * POC_REWARDS_PERCENT; let data_transfer = total_emission_pool * MAX_DATA_TRANSFER_REWARDS_PERCENT; @@ -754,27 +752,22 @@ impl CalculatedPocRewardShares { } } -pub fn get_total_scheduled_tokens(duration: Duration) -> Decimal { - (TOTAL_EMISSIONS_POOL / dec!(365) / Decimal::from(Duration::hours(24).num_seconds())) - * Decimal::from(duration.num_seconds()) -} - -pub fn get_scheduled_tokens_for_poc(duration: Duration) -> Decimal { +pub fn get_scheduled_tokens_for_poc(total_emission_pool: Decimal) -> Decimal { let poc_percent = MAX_DATA_TRANSFER_REWARDS_PERCENT + POC_REWARDS_PERCENT + BOOSTED_POC_REWARDS_PERCENT; - get_total_scheduled_tokens(duration) * poc_percent + total_emission_pool * poc_percent } -pub fn get_scheduled_tokens_for_mappers(duration: Duration) -> Decimal { - get_total_scheduled_tokens(duration) * MAPPERS_REWARDS_PERCENT +pub fn get_scheduled_tokens_for_mappers(total_emission_pool: Decimal) -> Decimal { + total_emission_pool * MAPPERS_REWARDS_PERCENT } -pub fn get_scheduled_tokens_for_service_providers(duration: Duration) -> Decimal { - get_total_scheduled_tokens(duration) * SERVICE_PROVIDER_PERCENT +pub fn get_scheduled_tokens_for_service_providers(total_emission_pool: Decimal) -> Decimal { + total_emission_pool * SERVICE_PROVIDER_PERCENT } -pub fn get_scheduled_tokens_for_oracles(duration: Duration) -> Decimal { - get_total_scheduled_tokens(duration) * ORACLES_PERCENT +pub fn get_scheduled_tokens_for_oracles(total_emission_pool: Decimal) -> Decimal { + total_emission_pool * ORACLES_PERCENT } fn eligible_for_coverage_map( @@ -831,6 +824,9 @@ mod test { use std::collections::HashMap; use uuid::Uuid; + pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; + pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + fn hex_assignments_mock() -> HexAssignments { HexAssignments { footfall: Assignment::A, @@ -849,28 +845,32 @@ mod test { #[test] fn ensure_correct_conversion_of_bytes_to_bones() { - assert_eq!( - dc_to_mobile_bones(Decimal::from(1), dec!(1.0)), - dec!(0.00001) - ); - assert_eq!( - dc_to_mobile_bones(Decimal::from(2), dec!(1.0)), - dec!(0.00002) - ); + assert_eq!(dc_to_hnt_bones(Decimal::from(1), dec!(1.0)), dec!(0.00001)); + assert_eq!(dc_to_hnt_bones(Decimal::from(2), dec!(1.0)), dec!(0.00002)); + } + + fn hnt_bones_to_dc(hnt_bones_amount: Decimal, hnt_bones_price: Decimal) -> Decimal { + let hnt_value = hnt_bones_amount * hnt_bones_price; + (hnt_value / DC_USD_PRICE).round_dp_with_strategy(0, RoundingStrategy::ToNegativeInfinity) } - fn mobile_bones_to_dc(mobile_bones_amount: Decimal, mobile_bones_price: Decimal) -> Decimal { - let mobile_value = mobile_bones_amount * mobile_bones_price; - (mobile_value / DC_USD_PRICE) - .round_dp_with_strategy(0, RoundingStrategy::ToNegativeInfinity) + fn default_rewards_info( + total_emissions: u64, + epoch_duration: Duration, + ) -> ResolvedSubDaoEpochRewardInfo { + let now = Utc::now(); + ResolvedSubDaoEpochRewardInfo { + epoch: 1, + epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_period: (now - epoch_duration)..now, + epoch_emissions: Decimal::from(total_emissions), + rewards_issued_at: now, + } } #[tokio::test] async fn subscriber_rewards() { - // test based on example defined at https://github.com/helium/oracles/issues/422 - // NOTE: the example defined above lists values in mobile tokens, whereas - // this test uses mobile bones - const NUM_SUBSCRIBERS: u64 = 10_000; // simulate 10k subscriber location shares @@ -888,25 +888,17 @@ mod test { }); } - // calculate discovery mapping rewards for a 24hr period - let now = Utc::now(); - let epoch = (now - Duration::hours(24))..now; + // set our rewards info + let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // translate location shares into shares let shares = MapperShares::new(location_shares, vsme_shares); let total_mappers_pool = - reward_shares::get_scheduled_tokens_for_mappers(epoch.end - epoch.start); + reward_shares::get_scheduled_tokens_for_mappers(rewards_info.epoch_emissions); let rewards_per_share = shares.rewards_per_share(total_mappers_pool).unwrap(); - // verify total rewards for the epoch - let total_epoch_rewards = get_total_scheduled_tokens(epoch.end - epoch.start) - .round_dp_with_strategy(0, RoundingStrategy::ToZero) - .to_u64() - .unwrap_or(0); - assert_eq!(82_191_780_821_917, total_epoch_rewards); - // verify total rewards allocated to mappers the epoch - let total_mapper_rewards = get_scheduled_tokens_for_mappers(epoch.end - epoch.start) + let total_mapper_rewards = get_scheduled_tokens_for_mappers(rewards_info.epoch_emissions) .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0); @@ -917,7 +909,7 @@ mod test { // get the summed rewards allocated to subscribers for discovery location let mut allocated_mapper_rewards = 0_u64; for (reward_amount, subscriber_share) in - shares.into_subscriber_rewards(&epoch, rewards_per_share) + shares.into_subscriber_rewards(&rewards_info, rewards_per_share) { if let Some(MobileReward::SubscriberReward(r)) = subscriber_share.reward { assert_eq!( @@ -975,9 +967,9 @@ mod test { }, ); - let now = Utc::now(); - let epoch = (now - Duration::hours(1))..now; - let total_rewards = get_scheduled_tokens_for_poc(epoch.end - epoch.start); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let total_rewards = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions); // confirm our hourly rewards add up to expected 24hr amount // total_rewards will be in bones @@ -986,7 +978,8 @@ mod test { dec!(49_315_068) ); - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(&epoch); + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); let data_transfer_rewards = TransferRewards::from_transfer_sessions(dec!(1.0), data_transfer_map, &reward_shares) @@ -994,12 +987,14 @@ mod test { assert_eq!(data_transfer_rewards.reward(&owner), dec!(0.00002)); assert_eq!(data_transfer_rewards.reward_scale(), dec!(1.0)); - let available_poc_rewards = get_scheduled_tokens_for_poc(epoch.end - epoch.start) + + let available_poc_rewards = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions) - data_transfer_rewards.reward_sum; + assert_eq!( available_poc_rewards, - total_rewards - - (data_transfer_rewards.reward(&owner) * data_transfer_rewards.reward_scale()) + (total_rewards + - (data_transfer_rewards.reward(&owner) * data_transfer_rewards.reward_scale())) ); } @@ -1031,10 +1026,11 @@ mod test { .await .unwrap(); - let now = Utc::now(); - let epoch = (now - Duration::hours(24))..now; + // set our rewards info + let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(&epoch); + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); let data_transfer_rewards = TransferRewards::from_transfer_sessions( dec!(1.0), @@ -1047,13 +1043,13 @@ mod test { // allotted reward amount for data transfer, which is 40% of the daily tokens. We check to // ensure that amount of tokens remaining for POC is no less than 20% of the rewards allocated // for POC and data transfer (which is 60% of the daily total emissions). - let available_poc_rewards = get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let available_poc_rewards = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions) - data_transfer_rewards.reward_sum; assert_eq!(available_poc_rewards.trunc(), dec!(16_438_356_164_383)); assert_eq!( // Rewards are automatically scaled data_transfer_rewards.reward(&owner).trunc(), - dec!(32_876_712_328_767) + dec!(32_876_712_328_766) ); assert_eq!(data_transfer_rewards.reward_scale().round_dp(1), dec!(0.5)); } @@ -1242,11 +1238,11 @@ mod test { let speedtest_avgs = SpeedtestAverages { averages }; - let duration = Duration::hours(1); - let epoch = (now - duration)..now; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); - let epoch = (now - Duration::hours(1))..now; let (_reward_amount, _mobile_reward_v1, mobile_reward_v2) = CoverageShares::new( &hex_coverage, stream::iter(heartbeat_rewards), @@ -1255,11 +1251,11 @@ mod test { &BoostedHexEligibility::default(), &BannedRadios::default(), &UniqueConnectionCounts::default(), - &epoch, + &rewards_info.epoch_period, ) .await .unwrap() - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .unwrap() .1 .next() @@ -1644,9 +1640,10 @@ mod test { // calculate the rewards for the sample group let mut owner_rewards = HashMap::::new(); - let duration = Duration::hours(1); - let epoch = (now - duration)..now; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); let mut allocated_poc_rewards = 0_u64; @@ -1663,7 +1660,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .unwrap() .1 { @@ -1740,7 +1737,7 @@ mod test { .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0); - assert_eq!(unallocated_sp_reward_amount, 9); + assert_eq!(unallocated_sp_reward_amount, 10); } #[tokio::test] @@ -1828,10 +1825,11 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let duration = Duration::hours(1); - let epoch = (now - duration)..now; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in CoverageShares::new( &hex_coverage, @@ -1841,11 +1839,11 @@ mod test { &BoostedHexEligibility::default(), &BannedRadios::default(), &UniqueConnectionCounts::default(), - &epoch, + &rewards_info.epoch_period, ) .await .unwrap() - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .unwrap() .1 { @@ -1964,10 +1962,11 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let duration = Duration::hours(1); - let epoch = (now - duration)..now; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in CoverageShares::new( &hex_coverage, stream::iter(heartbeat_rewards), @@ -1976,11 +1975,11 @@ mod test { &BoostedHexEligibility::default(), &BannedRadios::default(), &UniqueConnectionCounts::default(), - &epoch, + &rewards_info.epoch_period, ) .await .unwrap() - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .unwrap() .1 { @@ -2100,10 +2099,11 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let duration = Duration::hours(1); - let epoch = (now - duration)..now; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in CoverageShares::new( &hex_coverage, stream::iter(heartbeat_rewards), @@ -2112,11 +2112,11 @@ mod test { &BoostedHexEligibility::default(), &BannedRadios::default(), &UniqueConnectionCounts::default(), - &epoch, + &rewards_info.epoch_period, ) .await .unwrap() - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .unwrap() .1 { @@ -2288,7 +2288,7 @@ mod test { let now = Utc::now(); // We should never see any radio shares from owner2, since all of them are // less than or equal to zero. - let epoch = now - Duration::hours(1)..now; + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); let uuid_1 = Uuid::new_v4(); let uuid_2 = Uuid::new_v4(); @@ -2318,7 +2318,8 @@ mod test { assignments: hex_assignments_mock(), }], }); - let coverage_map = coverage_map.build(&BoostedHexes::default(), epoch.start); + let coverage_map = + coverage_map.build(&BoostedHexes::default(), rewards_info.epoch_period.start); let mut radio_infos = HashMap::new(); radio_infos.insert( @@ -2382,11 +2383,12 @@ mod test { radio_infos, }; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); // gw2 does not have enough speedtests for a mulitplier let expected_hotspot = gw1; for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in coverage_shares - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .expect("rewards output") .1 { @@ -2401,36 +2403,35 @@ mod test { #[tokio::test] async fn skip_empty_radio_rewards() { - let now = Utc::now(); - let epoch = now - Duration::hours(1)..now; + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); let coverage_shares = CoverageShares { coverage_map: coverage_map::CoverageMapBuilder::default() - .build(&BoostedHexes::default(), epoch.start), + .build(&BoostedHexes::default(), rewards_info.epoch_period.start), radio_infos: HashMap::new(), }; - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); assert!(coverage_shares - .into_rewards(reward_shares, &epoch) + .into_rewards(reward_shares, &rewards_info) .is_none()); } #[test] fn service_provider_reward_amounts() { - let mobile_bone_price = dec!(0.00001); + let hnt_bone_price = dec!(0.00001); let sp1 = ServiceProvider::HeliumMobile; - let now = Utc::now(); - let epoch = (now - Duration::hours(1))..now; + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); - let total_sp_rewards = service_provider::get_scheduled_tokens(&epoch); + let total_sp_rewards = service_provider::get_scheduled_tokens(rewards_info.epoch_emissions); let sp_reward_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(sp1, dec!(1000))]), ServiceProviderPromotions::default(), total_sp_rewards, - mobile_bone_price, - epoch.clone(), + hnt_bone_price, + rewards_info.clone(), ); let mut sp_rewards = HashMap::::new(); @@ -2447,35 +2448,33 @@ mod test { let sp1_reward_amount = *sp_rewards .get(&(sp1 as i32)) .expect("Could not fetch sp1 shares"); - assert_eq!(sp1_reward_amount, 1000); + assert_eq!(sp1_reward_amount, 999); // confirm the unallocated service provider reward amounts let unallocated_sp_reward_amount = (total_sp_rewards - Decimal::from(allocated_sp_rewards)) .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0); - assert_eq!(unallocated_sp_reward_amount, 342_465_752_424); + assert_eq!(unallocated_sp_reward_amount, 342_465_752_425); } #[test] fn service_provider_reward_amounts_capped() { - let mobile_bone_price = dec!(1.0); + let hnt_bone_price = dec!(1.0); let sp1 = ServiceProvider::HeliumMobile; - let now = Utc::now(); - let epoch = (now - Duration::hours(1))..now; + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); - let total_sp_rewards_in_bones = dec!(100_000_000); - let total_rewards_value_in_dc = - mobile_bones_to_dc(total_sp_rewards_in_bones, mobile_bone_price); + let total_sp_rewards_in_bones = dec!(1_0000_0000); + let total_rewards_value_in_dc = hnt_bones_to_dc(total_sp_rewards_in_bones, hnt_bone_price); let sp_reward_infos = ServiceProviderRewardInfos::new( // force the service provider to have spend more DC than total rewardable ServiceProviderDCSessions::from([(sp1, total_rewards_value_in_dc * dec!(2.0))]), ServiceProviderPromotions::default(), total_sp_rewards_in_bones, - mobile_bone_price, - epoch.clone(), + hnt_bone_price, + rewards_info.clone(), ); let mut sp_rewards = HashMap::new(); @@ -2494,7 +2493,7 @@ mod test { .expect("Could not fetch sp1 shares"); assert_eq!(Decimal::from(sp1_reward_amount), total_sp_rewards_in_bones); - assert_eq!(sp1_reward_amount, 100_000_000); + assert_eq!(sp1_reward_amount, 1_0000_0000); // confirm the unallocated service provider reward amounts let unallocated_sp_reward_amount = (total_sp_rewards_in_bones @@ -2507,20 +2506,20 @@ mod test { #[test] fn service_provider_reward_hip87_ex1() { - // mobile price from hip example and converted to bones - let mobile_bone_price = dec!(0.0001) / dec!(1_000_000); + // hnt price from hip example and converted to bones + let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let now = Utc::now(); - let epoch = (now - Duration::hours(1))..now; - let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_000_000); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + + let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); let sp_reward_infos = ServiceProviderRewardInfos::new( - ServiceProviderDCSessions::from([(sp1, dec!(100_000_000))]), + ServiceProviderDCSessions::from([(sp1, dec!(1_0000_0000))]), ServiceProviderPromotions::default(), total_sp_rewards_in_bones, - mobile_bone_price, - epoch.clone(), + hnt_bone_price, + rewards_info.clone(), ); let mut sp_rewards = HashMap::new(); @@ -2537,9 +2536,8 @@ mod test { let sp1_reward_amount_in_bones = *sp_rewards .get(&(sp1 as i32)) .expect("Could not fetch sp1 shares"); - // example in HIP gives expected reward amount in mobile whereas we use bones // assert expected value in bones - assert_eq!(sp1_reward_amount_in_bones, 10_000_000 * 1_000_000); + assert_eq!(sp1_reward_amount_in_bones, 10_000_000 * 1_0000_0000); // confirm the unallocated service provider reward amounts let unallocated_sp_reward_amount = (total_sp_rewards_in_bones @@ -2547,25 +2545,24 @@ mod test { .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0); - assert_eq!(unallocated_sp_reward_amount, 490_000_000_000_000); + assert_eq!(unallocated_sp_reward_amount, 490_00_000_000_000_000); } #[test] fn service_provider_reward_hip87_ex2() { - // mobile price from hip example and converted to bones - let mobile_bone_price = dec!(0.0001) / dec!(1_000_000); + // hnt price from hip example and converted to bones + let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let now = Utc::now(); - let epoch = (now - Duration::hours(24))..now; - let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_000_000); + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(24)); + let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); let sp_reward_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(sp1, dec!(100_000_000_000))]), ServiceProviderPromotions::default(), total_sp_rewards_in_bones, - mobile_bone_price, - epoch.clone(), + hnt_bone_price, + rewards_info.clone(), ); let mut sp_rewards = HashMap::new(); @@ -2582,9 +2579,8 @@ mod test { let sp1_reward_amount_in_bones = *sp_rewards .get(&(sp1 as i32)) .expect("Could not fetch sp1 shares"); - // example in HIP gives expected reward amount in mobile whereas we use bones // assert expected value in bones - assert_eq!(sp1_reward_amount_in_bones, 500_000_000 * 1_000_000); + assert_eq!(sp1_reward_amount_in_bones, 500_000_000 * 1_0000_0000); // confirm the unallocated service provider reward amounts let unallocated_sp_reward_amount = (total_sp_rewards_in_bones diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index ddcd25d4d..665d9a9dd 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -11,7 +11,7 @@ use crate::{ sp_boosted_rewards_bans, speedtests, speedtests_average::SpeedtestAverages, subscriber_location, subscriber_verified_mapping_event, telemetry, unique_connections, - Settings, + Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, }; use anyhow::bail; use chrono::{DateTime, TimeZone, Utc}; @@ -23,6 +23,8 @@ use file_store::{ }; use futures_util::TryFutureExt; +use self::boosted_hex_eligibility::BoostedHexEligibility; +use helium_crypto::PublicKeyBinary; use helium_proto::{ reward_manifest::RewardData::MobileRewardData, services::poc_mobile::{ @@ -36,8 +38,10 @@ use mobile_config::{ boosted_hex_info::BoostedHexes, client::{ carrier_service_client::CarrierServiceVerifier, - hex_boosting_client::HexBoostingInfoResolver, ClientError, + hex_boosting_client::HexBoostingInfoResolver, + sub_dao_client::SubDaoEpochRewardInfoResolver, ClientError, }, + sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo, }; use price::PriceTracker; use reward_scheduler::Scheduler; @@ -48,17 +52,17 @@ use std::{ops::Range, time::Duration}; use task_manager::{ManagedTask, TaskManager}; use tokio::time::sleep; -use self::boosted_hex_eligibility::BoostedHexEligibility; - pub mod boosted_hex_eligibility; mod db; const REWARDS_NOT_CURRENT_DELAY_PERIOD: i64 = 5; -pub struct Rewarder { +pub struct Rewarder { + sub_dao_pubkey: PublicKeyBinary, pool: Pool, carrier_client: A, hex_service_client: B, + sub_dao_epoch_reward_client: C, reward_period_duration: Duration, reward_offset: Duration, pub mobile_rewards: FileSinkClient, @@ -67,10 +71,11 @@ pub struct Rewarder { speedtest_averages: FileSinkClient, } -impl Rewarder +impl Rewarder where A: CarrierServiceVerifier + Send + Sync + 'static, B: HexBoostingInfoResolver + Send + Sync + 'static, + C: SubDaoEpochRewardInfoResolver + Send + Sync + 'static, { pub async fn create_managed_task( pool: Pool, @@ -78,6 +83,7 @@ where file_upload: FileUpload, carrier_service_verifier: A, hex_boosting_info_resolver: B, + sub_dao_epoch_reward_info_resolver: C, speedtests_avg: FileSinkClient, ) -> anyhow::Result { let (price_tracker, price_daemon) = PriceTracker::new_tm(&settings.price_tracker).await?; @@ -104,13 +110,14 @@ where pool.clone(), carrier_service_verifier, hex_boosting_info_resolver, + sub_dao_epoch_reward_info_resolver, settings.reward_period, settings.reward_period_offset, mobile_rewards, reward_manifests, price_tracker, speedtests_avg, - ); + )?; Ok(TaskManager::builder() .add_task(price_daemon) @@ -125,40 +132,52 @@ where pool: Pool, carrier_client: A, hex_service_client: B, + sub_dao_epoch_reward_client: C, reward_period_duration: Duration, reward_offset: Duration, mobile_rewards: FileSinkClient, reward_manifests: FileSinkClient, price_tracker: PriceTracker, speedtest_averages: FileSinkClient, - ) -> Self { - Self { + ) -> anyhow::Result { + let sub_dao_pubkey = PublicKeyBinary::from_str(MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; + Ok(Self { + sub_dao_pubkey, pool, carrier_client, hex_service_client, + sub_dao_epoch_reward_client, reward_period_duration, reward_offset, mobile_rewards, reward_manifests, price_tracker, speedtest_averages, - } + }) } pub async fn run(self, shutdown: triggered::Listener) -> anyhow::Result<()> { loop { - let last_rewarded_end_time = last_rewarded_end_time(&self.pool).await?; - let next_rewarded_end_time = next_rewarded_end_time(&self.pool).await?; + let next_reward_epoch = next_reward_epoch(&self.pool).await?; + let reward_info = self + .sub_dao_epoch_reward_client + .resolve_info(&self.sub_dao_pubkey, next_reward_epoch) + .await? + .ok_or(anyhow::anyhow!( + "No reward info found for epoch {}", + next_reward_epoch + ))?; + let scheduler = Scheduler::new( self.reward_period_duration, - last_rewarded_end_time, - next_rewarded_end_time, + reward_info.epoch_period.start, + reward_info.epoch_period.end, self.reward_offset, ); let now = Utc::now(); - let sleep_duration = if scheduler.should_reward(now) { - if self.is_data_current(&scheduler.reward_period).await? { - self.reward(&scheduler).await?; + let sleep_duration = if scheduler.should_trigger(now) { + if self.is_data_current(&scheduler.schedule_period).await? { + self.reward(reward_info).await?; continue; } else { chrono::Duration::minutes(REWARDS_NOT_CURRENT_DELAY_PERIOD).to_std()? @@ -228,24 +247,23 @@ where Ok(true) } - pub async fn reward(&self, scheduler: &Scheduler) -> anyhow::Result<()> { - let reward_period = &scheduler.reward_period; - + pub async fn reward(&self, reward_info: ResolvedSubDaoEpochRewardInfo) -> anyhow::Result<()> { tracing::info!( - "Rewarding for period: {} to {}", - reward_period.start, - reward_period.end + "Rewarding for epoch {} period: {} to {}", + reward_info.epoch, + reward_info.epoch_period.start, + reward_info.epoch_period.end ); - let mobile_price = self + let hnt_price = self .price_tracker - .price(&helium_proto::BlockchainTokenTypeV1::Mobile) + .price(&helium_proto::BlockchainTokenTypeV1::Hnt) .await?; - // Mobile prices are supplied in 10^6, so we must convert them to Decimal - let mobile_bone_price = Decimal::from(mobile_price) - / dec!(1_000_000) // Per Mobile token - / dec!(1_000_000); // Per Bone + // Hnt prices are supplied in 10^8, so we must convert them to Decimal + let hnt_bone_price = Decimal::from(hnt_price) + / dec!(1_0000_0000) // Per Hnt token + / dec!(1_0000_0000); // Per Bone // process rewards for poc and data transfer let poc_dc_shares = reward_poc_and_dc( @@ -253,49 +271,58 @@ where &self.hex_service_client, &self.mobile_rewards, &self.speedtest_averages, - reward_period, - mobile_bone_price, + &reward_info, + hnt_bone_price, ) .await?; // process rewards for mappers - reward_mappers(&self.pool, &self.mobile_rewards, reward_period).await?; + reward_mappers(&self.pool, &self.mobile_rewards, &reward_info).await?; // process rewards for service providers - let dc_sessions = - service_provider::get_dc_sessions(&self.pool, &self.carrier_client, reward_period) - .await?; + let dc_sessions = service_provider::get_dc_sessions( + &self.pool, + &self.carrier_client, + &reward_info.epoch_period, + ) + .await?; let sp_promotions = - service_provider::get_promotions(&self.carrier_client, &reward_period.start).await?; + service_provider::get_promotions(&self.carrier_client, &reward_info.epoch_period.start) + .await?; reward_service_providers( dc_sessions, sp_promotions.clone(), &self.mobile_rewards, - reward_period, - mobile_bone_price, + &reward_info, + hnt_bone_price, ) .await?; // process rewards for oracles - reward_oracles(&self.mobile_rewards, reward_period).await?; + reward_oracles(&self.mobile_rewards, &reward_info).await?; self.speedtest_averages.commit().await?; let written_files = self.mobile_rewards.commit().await?.await??; let mut transaction = self.pool.begin().await?; // clear out the various db tables - heartbeats::clear_heartbeats(&mut transaction, &reward_period.start).await?; - speedtests::clear_speedtests(&mut transaction, &reward_period.start).await?; - data_session::clear_hotspot_data_sessions(&mut transaction, &reward_period.start).await?; - coverage::clear_coverage_objects(&mut transaction, &reward_period.start).await?; - sp_boosted_rewards_bans::clear_bans(&mut transaction, reward_period.start).await?; - subscriber_verified_mapping_event::clear(&mut transaction, &reward_period.start).await?; - unique_connections::db::clear(&mut transaction, &reward_period.start).await?; + heartbeats::clear_heartbeats(&mut transaction, &reward_info.epoch_period.start).await?; + speedtests::clear_speedtests(&mut transaction, &reward_info.epoch_period.start).await?; + data_session::clear_hotspot_data_sessions( + &mut transaction, + &reward_info.epoch_period.start, + ) + .await?; + coverage::clear_coverage_objects(&mut transaction, &reward_info.epoch_period.start).await?; + sp_boosted_rewards_bans::clear_bans(&mut transaction, reward_info.epoch_period.start) + .await?; + subscriber_verified_mapping_event::clear(&mut transaction, &reward_info.epoch_period.start) + .await?; + unique_connections::db::clear(&mut transaction, &reward_info.epoch_period.start).await?; // subscriber_location::clear_location_shares(&mut transaction, &reward_period.end).await?; - let next_reward_period = scheduler.next_reward_period(); - save_last_rewarded_end_time(&mut transaction, &next_reward_period.start).await?; - save_next_rewarded_end_time(&mut transaction, &next_reward_period.end).await?; + save_next_reward_epoch(&mut transaction, reward_info.epoch + 1).await?; + transaction.commit().await?; // now that the db has been purged, safe to write out the manifest @@ -311,10 +338,11 @@ where self.reward_manifests .write( RewardManifest { - start_timestamp: reward_period.start.encode_timestamp(), - end_timestamp: reward_period.end.encode_timestamp(), + start_timestamp: reward_info.epoch_period.start.encode_timestamp(), + end_timestamp: reward_info.epoch_period.end.encode_timestamp(), written_files, reward_data: Some(MobileRewardData(reward_data)), + epoch: reward_info.epoch, }, [], ) @@ -322,15 +350,16 @@ where .await??; self.reward_manifests.commit().await?; - telemetry::last_rewarded_end_time(next_reward_period.start); + telemetry::last_rewarded_end_time(reward_info.epoch_period.end); Ok(()) } } -impl ManagedTask for Rewarder +impl ManagedTask for Rewarder where A: CarrierServiceVerifier + Send + Sync + 'static, B: HexBoostingInfoResolver + Send + Sync + 'static, + C: SubDaoEpochRewardInfoResolver + Send + Sync + 'static, { fn start_task( self: Box, @@ -350,14 +379,16 @@ pub async fn reward_poc_and_dc( hex_service_client: &impl HexBoostingInfoResolver, mobile_rewards: &FileSinkClient, speedtest_avg_sink: &FileSinkClient, - reward_period: &Range>, - mobile_bone_price: Decimal, + reward_info: &ResolvedSubDaoEpochRewardInfo, + hnt_bone_price: Decimal, ) -> anyhow::Result { - let mut reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(reward_period); + let mut reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new(reward_info.epoch_emissions); let transfer_rewards = TransferRewards::from_transfer_sessions( - mobile_bone_price, - data_session::aggregate_hotspot_data_sessions_to_dc(pool, reward_period).await?, + hnt_bone_price, + data_session::aggregate_hotspot_data_sessions_to_dc(pool, &reward_info.epoch_period) + .await?, &reward_shares, ) .await; @@ -373,7 +404,7 @@ pub async fn reward_poc_and_dc( // and carry this into the poc pool let dc_unallocated_amount = reward_dc( mobile_rewards, - reward_period, + reward_info, transfer_rewards, &reward_shares, ) @@ -385,7 +416,7 @@ pub async fn reward_poc_and_dc( hex_service_client, mobile_rewards, speedtest_avg_sink, - reward_period, + reward_info, reward_shares, ) .await?; @@ -399,7 +430,7 @@ pub async fn reward_poc_and_dc( mobile_rewards, UnallocatedRewardType::Poc, poc_unallocated_amount, - reward_period, + reward_info, ) .await?; @@ -411,12 +442,12 @@ async fn reward_poc( hex_service_client: &impl HexBoostingInfoResolver, mobile_rewards: &FileSinkClient, speedtest_avg_sink: &FileSinkClient, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, reward_shares: DataTransferAndPocAllocatedRewardBuckets, ) -> anyhow::Result<(Decimal, CalculatedPocRewardShares)> { - let heartbeats = HeartbeatReward::validated(pool, reward_period); + let heartbeats = HeartbeatReward::validated(pool, &reward_info.epoch_period); let speedtest_averages = - SpeedtestAverages::aggregate_epoch_averages(reward_period.end, pool).await?; + SpeedtestAverages::aggregate_epoch_averages(reward_info.epoch_period.end, pool).await?; speedtest_averages.write_all(speedtest_avg_sink).await?; @@ -425,11 +456,11 @@ async fn reward_poc( let unique_connections = unique_connections::db::get(pool, reward_period).await?; let boosted_hex_eligibility = BoostedHexEligibility::new( - radio_threshold::verified_radio_thresholds(pool, reward_period).await?, + radio_threshold::verified_radio_thresholds(pool, &reward_info.epoch_period).await?, sp_boosted_rewards_bans::db::get_banned_radios( pool, SpBoostedRewardsBannedRadioBanType::BoostedHex, - reward_period.end, + reward_info.epoch_period.end, ) .await?, unique_connections.clone(), @@ -438,7 +469,7 @@ async fn reward_poc( let poc_banned_radios = sp_boosted_rewards_bans::db::get_banned_radios( pool, SpBoostedRewardsBannedRadioBanType::Poc, - reward_period.end, + reward_info.epoch_period.end, ) .await?; @@ -450,7 +481,7 @@ async fn reward_poc( &boosted_hex_eligibility, &poc_banned_radios, &unique_connections, - reward_period, + &reward_info.epoch_period, ) .await?; @@ -458,7 +489,7 @@ async fn reward_poc( let (unallocated_poc_amount, calculated_poc_rewards_per_share) = if let Some((calculated_poc_rewards_per_share, mobile_reward_shares)) = - coverage_shares.into_rewards(reward_shares, reward_period) + coverage_shares.into_rewards(reward_shares, reward_info) { // handle poc reward outputs let mut allocated_poc_rewards = 0_u64; @@ -491,13 +522,13 @@ async fn reward_poc( pub async fn reward_dc( mobile_rewards: &FileSinkClient, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, transfer_rewards: TransferRewards, reward_shares: &DataTransferAndPocAllocatedRewardBuckets, ) -> anyhow::Result { // handle dc reward outputs let mut allocated_dc_rewards = 0_u64; - for (dc_reward_amount, mobile_reward_share) in transfer_rewards.into_rewards(reward_period) { + for (dc_reward_amount, mobile_reward_share) in transfer_rewards.into_rewards(reward_info) { allocated_dc_rewards += dc_reward_amount; mobile_rewards .write(mobile_reward_share, []) @@ -516,34 +547,36 @@ pub async fn reward_dc( pub async fn reward_mappers( pool: &Pool, mobile_rewards: &FileSinkClient, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, ) -> anyhow::Result<()> { // Mapper rewards currently include rewards for discovery mapping only. // Verification mapping rewards to be added // get subscriber location shares this epoch let location_shares = - subscriber_location::aggregate_location_shares(pool, reward_period).await?; + subscriber_location::aggregate_location_shares(pool, &reward_info.epoch_period).await?; // Verification mappers can only earn rewards if they qualified for disco mapping // rewards during the same reward_period - let vsme_shares = - subscriber_verified_mapping_event::aggregate_verified_mapping_events(pool, reward_period) - .await? - .into_iter() - .filter(|vsme| location_shares.contains(&vsme.subscriber_id)) - .collect(); + let vsme_shares = subscriber_verified_mapping_event::aggregate_verified_mapping_events( + pool, + &reward_info.epoch_period, + ) + .await? + .into_iter() + .filter(|vsme| location_shares.contains(&vsme.subscriber_id)) + .collect(); // determine mapping shares based on location shares and data transferred let mapping_shares = MapperShares::new(location_shares, vsme_shares); let total_mappers_pool = - reward_shares::get_scheduled_tokens_for_mappers(reward_period.end - reward_period.start); + reward_shares::get_scheduled_tokens_for_mappers(reward_info.epoch_emissions); let rewards_per_share = mapping_shares.rewards_per_share(total_mappers_pool)?; // translate discovery mapping shares into subscriber rewards let mut allocated_mapping_rewards = 0_u64; for (reward_amount, mapping_share) in - mapping_shares.into_subscriber_rewards(reward_period, rewards_per_share) + mapping_shares.into_subscriber_rewards(reward_info, rewards_per_share) { allocated_mapping_rewards += reward_amount; mobile_rewards @@ -563,7 +596,7 @@ pub async fn reward_mappers( mobile_rewards, UnallocatedRewardType::Mapper, unallocated_mapping_reward_amount, - reward_period, + reward_info, ) .await?; @@ -572,11 +605,11 @@ pub async fn reward_mappers( pub async fn reward_oracles( mobile_rewards: &FileSinkClient, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, ) -> anyhow::Result<()> { // atm 100% of oracle rewards are assigned to 'unallocated' let total_oracle_rewards = - reward_shares::get_scheduled_tokens_for_oracles(reward_period.end - reward_period.start); + reward_shares::get_scheduled_tokens_for_oracles(reward_info.epoch_emissions); let allocated_oracle_rewards = 0_u64; let unallocated_oracle_reward_amount = total_oracle_rewards .round_dp_with_strategy(0, RoundingStrategy::ToZero) @@ -587,7 +620,7 @@ pub async fn reward_oracles( mobile_rewards, UnallocatedRewardType::Oracle, unallocated_oracle_reward_amount, - reward_period, + reward_info, ) .await?; Ok(()) @@ -597,19 +630,19 @@ pub async fn reward_service_providers( dc_sessions: ServiceProviderDCSessions, sp_promotions: ServiceProviderPromotions, mobile_rewards: &FileSinkClient, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, mobile_bone_price: Decimal, ) -> anyhow::Result<()> { use service_provider::ServiceProviderRewardInfos; - let total_sp_rewards = service_provider::get_scheduled_tokens(reward_period); + let total_sp_rewards = service_provider::get_scheduled_tokens(reward_info.epoch_emissions); let sps = ServiceProviderRewardInfos::new( dc_sessions, sp_promotions, total_sp_rewards, mobile_bone_price, - reward_period.clone(), + reward_info.clone(), ); let mut unallocated_sp_rewards = total_sp_rewards @@ -627,7 +660,7 @@ pub async fn reward_service_providers( mobile_rewards, UnallocatedRewardType::ServiceProvider, unallocated_sp_rewards, - reward_period, + reward_info, ) .await?; Ok(()) @@ -637,12 +670,13 @@ async fn write_unallocated_reward( mobile_rewards: &FileSinkClient, unallocated_type: UnallocatedRewardType, unallocated_amount: u64, - reward_period: &'_ Range>, + reward_info: &'_ ResolvedSubDaoEpochRewardInfo, ) -> anyhow::Result<()> { if unallocated_amount > 0 { let unallocated_reward = proto::MobileRewardShare { - start_period: reward_period.start.encode_timestamp(), - end_period: reward_period.end.encode_timestamp(), + start_period: reward_info.epoch_period.start.encode_timestamp(), + end_period: reward_info.epoch_period.end.encode_timestamp(), + epoch: reward_info.epoch, reward: Some(ProtoReward::UnallocatedReward(UnallocatedReward { reward_type: unallocated_type as i32, amount: unallocated_amount, @@ -656,28 +690,10 @@ async fn write_unallocated_reward( Ok(()) } -pub async fn last_rewarded_end_time(db: &Pool) -> db_store::Result> { - Utc.timestamp_opt(meta::fetch(db, "last_rewarded_end_time").await?, 0) - .single() - .ok_or(db_store::Error::DecodeError) -} - -async fn next_rewarded_end_time(db: &Pool) -> db_store::Result> { - Utc.timestamp_opt(meta::fetch(db, "next_rewarded_end_time").await?, 0) - .single() - .ok_or(db_store::Error::DecodeError) -} - -async fn save_last_rewarded_end_time( - exec: impl PgExecutor<'_>, - value: &DateTime, -) -> db_store::Result<()> { - meta::store(exec, "last_rewarded_end_time", value.timestamp()).await +pub async fn next_reward_epoch(db: &Pool) -> db_store::Result { + meta::fetch(db, "next_reward_epoch").await } -async fn save_next_rewarded_end_time( - exec: impl PgExecutor<'_>, - value: &DateTime, -) -> db_store::Result<()> { - meta::store(exec, "next_rewarded_end_time", value.timestamp()).await +async fn save_next_reward_epoch(exec: impl PgExecutor<'_>, value: u64) -> db_store::Result<()> { + meta::store(exec, "next_reward_epoch", value).await } diff --git a/mobile_verifier/src/service_provider/dc_sessions.rs b/mobile_verifier/src/service_provider/dc_sessions.rs index 7b56119b3..c7c47f373 100644 --- a/mobile_verifier/src/service_provider/dc_sessions.rs +++ b/mobile_verifier/src/service_provider/dc_sessions.rs @@ -7,7 +7,7 @@ use sqlx::PgPool; use crate::{ data_session, - reward_shares::{dc_to_mobile_bones, DEFAULT_PREC}, + reward_shares::{dc_to_hnt_bones, DEFAULT_PREC}, }; use super::ServiceProviderId; @@ -58,7 +58,7 @@ impl ServiceProviderDCSessions { // the total amount of DC spent across all service providers let total_sp_dc = self.all_transfer(); // the total amount of service provider rewards in bones based on the spent DC - let total_sp_rewards_used = dc_to_mobile_bones(total_sp_dc, mobile_bone_price); + let total_sp_rewards_used = dc_to_hnt_bones(total_sp_dc, mobile_bone_price); // cap the service provider rewards if used > pool total let capped_sp_rewards_used = Self::maybe_cap_service_provider_rewards(total_sp_rewards_used, total_sp_rewards); diff --git a/mobile_verifier/src/service_provider/mod.rs b/mobile_verifier/src/service_provider/mod.rs index 19439df37..e45b4e15d 100644 --- a/mobile_verifier/src/service_provider/mod.rs +++ b/mobile_verifier/src/service_provider/mod.rs @@ -1,21 +1,39 @@ -use std::ops::Range; - -use chrono::{DateTime, Utc}; - +use chrono::{Duration, Utc}; pub use dc_sessions::{get_dc_sessions, ServiceProviderDCSessions}; +use helium_crypto::PublicKeyBinary; +use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; pub use promotions::{get_promotions, ServiceProviderPromotions}; pub use reward::ServiceProviderRewardInfos; +use rust_decimal::Decimal; +use std::str::FromStr; mod dc_sessions; mod promotions; mod reward; +pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; +pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + // This type is used in lieu of the helium_proto::ServiceProvider enum so we can // handle more than a single value without adding a hard deploy dependency to // mobile-verifier when a new carrier is added.. pub type ServiceProviderId = i32; -pub fn get_scheduled_tokens(reward_period: &Range>) -> rust_decimal::Decimal { - let duration = reward_period.end - reward_period.start; - crate::reward_shares::get_scheduled_tokens_for_service_providers(duration) +pub fn get_scheduled_tokens(total_emission_pool: Decimal) -> rust_decimal::Decimal { + crate::reward_shares::get_scheduled_tokens_for_service_providers(total_emission_pool) +} + +pub fn default_rewards_info( + total_emissions: u64, + epoch_duration: Duration, +) -> ResolvedSubDaoEpochRewardInfo { + let now = Utc::now(); + ResolvedSubDaoEpochRewardInfo { + epoch: 1, + epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_period: (now - epoch_duration)..now, + epoch_emissions: Decimal::from(total_emissions), + rewards_issued_at: now, + } } diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index 2f2f7733d..4cc9f8f0b 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -1,13 +1,9 @@ -use std::ops::Range; - -use chrono::{DateTime, Utc}; - +use crate::reward_shares::dc_to_hnt_bones; use file_store::traits::TimestampEncode; +use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; use rust_decimal::{Decimal, RoundingStrategy}; use rust_decimal_macros::dec; -use crate::reward_shares::dc_to_mobile_bones; - use super::{dc_sessions::ServiceProviderDCSessions, promotions::ServiceProviderPromotions}; mod proto { @@ -24,7 +20,7 @@ mod proto { pub struct ServiceProviderRewardInfos { coll: Vec, total_sp_allocation: Decimal, - reward_epoch: Range>, + reward_info: ResolvedSubDaoEpochRewardInfo, } // Represents a single Service Providers information for rewarding, @@ -57,15 +53,15 @@ impl ServiceProviderRewardInfos { dc_sessions: ServiceProviderDCSessions, promotions: ServiceProviderPromotions, total_sp_allocation: Decimal, // Bones - mobile_bone_price: Decimal, // Price in Bones - reward_epoch: Range>, + hnt_bone_price: Decimal, // Price in Bones + reward_info: ResolvedSubDaoEpochRewardInfo, ) -> Self { let all_transfer = dc_sessions.all_transfer(); // DC let mut me = Self { coll: vec![], total_sp_allocation, - reward_epoch, + reward_info, }; // After this point, we enter percentage land. This number is the basis @@ -76,7 +72,7 @@ impl ServiceProviderRewardInfos { // When rewards are output, the percentages are taken from the allocated // Bones for service providers. Which has the effect of scaling the rewards. let used_allocation = - total_sp_allocation.max(dc_to_mobile_bones(all_transfer, mobile_bone_price)); + total_sp_allocation.max(dc_to_hnt_bones(all_transfer, hnt_bone_price)); for (service_provider, dc_transfer) in dc_sessions.iter() { let promo_fund_perc = promotions.get_fund_percent(service_provider); @@ -84,7 +80,7 @@ impl ServiceProviderRewardInfos { me.coll.push(RewardInfo::new( service_provider, - dc_to_mobile_bones(dc_transfer, mobile_bone_price), + dc_to_hnt_bones(dc_transfer, hnt_bone_price), promo_fund_perc, used_allocation, promos, @@ -101,7 +97,7 @@ impl ServiceProviderRewardInfos { pub fn iter_rewards(&self) -> Vec<(u64, proto::MobileRewardShare)> { self.coll .iter() - .flat_map(|sp| sp.iter_rewards(self.total_sp_allocation, &self.reward_epoch)) + .flat_map(|sp| sp.iter_rewards(self.total_sp_allocation, &self.reward_info)) .filter(|(amount, _r)| *amount > 0) .collect::>() } @@ -140,25 +136,26 @@ impl RewardInfo { pub fn iter_rewards( &self, total_allocation: Decimal, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, ) -> Vec<(u64, proto::MobileRewardShare)> { - let mut rewards = self.promo_rewards(total_allocation, reward_period); - rewards.push(self.carrier_reward(total_allocation, reward_period)); + let mut rewards = self.promo_rewards(total_allocation, reward_info); + rewards.push(self.carrier_reward(total_allocation, reward_info)); rewards } pub fn carrier_reward( &self, total_allocation: Decimal, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, ) -> (u64, proto::MobileRewardShare) { let amount = (total_allocation * self.realized_data_perc).to_u64_floored(); // Rewarded BONES ( amount, proto::MobileRewardShare { - start_period: reward_period.start.encode_timestamp(), - end_period: reward_period.end.encode_timestamp(), + start_period: reward_info.epoch_period.start.encode_timestamp(), + end_period: reward_info.epoch_period.end.encode_timestamp(), + epoch: reward_info.epoch, reward: Some(proto::Reward::ServiceProviderReward( proto::ServiceProviderReward { service_provider_id: self.sp_id, @@ -172,7 +169,7 @@ impl RewardInfo { pub fn promo_rewards( &self, total_allocation: Decimal, - reward_period: &Range>, + reward_info: &ResolvedSubDaoEpochRewardInfo, ) -> Vec<(u64, proto::MobileRewardShare)> { if self.promotions.is_empty() { return vec![]; @@ -202,8 +199,9 @@ impl RewardInfo { rewards.push(( total_amount, proto::MobileRewardShare { - start_period: reward_period.start.encode_timestamp(), - end_period: reward_period.end.encode_timestamp(), + start_period: reward_info.epoch_period.start.encode_timestamp(), + end_period: reward_info.epoch_period.end.encode_timestamp(), + epoch: reward_info.epoch, reward: Some(proto::Reward::PromotionReward(proto::PromotionReward { service_provider_amount, matched_amount, @@ -272,26 +270,23 @@ impl DecimalRoundingExt for Decimal { #[cfg(test)] mod tests { - use chrono::Duration; + use chrono::{Duration, Utc}; use helium_proto::services::poc_mobile::{MobileRewardShare, PromotionReward}; use crate::service_provider; use super::*; - fn epoch() -> Range> { - let now = Utc::now(); - now - Duration::hours(24)..now - } - #[test] fn no_promotions() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dec!(12)), (1, dec!(6))]), ServiceProviderPromotions::default(), dec!(100), dec!(0.00001), - epoch(), + reward_info, ); let mut iter = sp_infos.iter_rewards().into_iter(); @@ -307,6 +302,7 @@ mod tests { #[test] fn unallocated_reward_scaling_1() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dec!(12)), (1, dec!(6))]), ServiceProviderPromotions::from(vec![ @@ -315,7 +311,7 @@ mod tests { ]), dec!(100), dec!(0.00001), - epoch(), + reward_info, ); let (promo_1, sp_1) = sp_infos.single_sp_rewards(0); @@ -331,6 +327,7 @@ mod tests { #[test] fn unallocated_reward_scaling_2() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dec!(12)), (1, dec!(6))]), ServiceProviderPromotions::from(vec![ @@ -355,7 +352,7 @@ mod tests { ]), dec!(100), dec!(0.00001), - epoch(), + reward_info, ); let (promo_1, sp_1) = sp_infos.single_sp_rewards(0); @@ -371,6 +368,7 @@ mod tests { #[test] fn unallocated_reward_scaling_3() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dec!(10)), (1, dec!(1000))]), ServiceProviderPromotions::from(vec![ @@ -379,7 +377,7 @@ mod tests { ]), dec!(2000), dec!(0.00001), - epoch(), + reward_info, ); let (promo_1, sp_1) = sp_infos.single_sp_rewards(0); @@ -395,12 +393,13 @@ mod tests { #[test] fn no_rewards_if_none_allocated() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dec!(100))]), ServiceProviderPromotions::from(vec![make_test_promotion(0, "promo-0", 5000, 1)]), dec!(0), dec!(0.0001), - epoch(), + reward_info, ); assert!(sp_infos.iter_rewards().is_empty()); @@ -408,6 +407,7 @@ mod tests { #[test] fn no_matched_rewards_if_no_unallocated() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let total_rewards = dec!(1000); let sp_infos = ServiceProviderRewardInfos::new( @@ -415,7 +415,7 @@ mod tests { ServiceProviderPromotions::from(vec![make_test_promotion(0, "promo-0", 5000, 1)]), total_rewards, dec!(0.00001), - epoch(), + reward_info, ); let promo_rewards = sp_infos.iter_rewards().only_promotion_rewards(); @@ -428,6 +428,7 @@ mod tests { #[test] fn single_sp_unallocated_less_than_matched_distributed_by_shares() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // 100 unallocated let total_rewards = dec!(1100); let sp_session = dec!(1000); @@ -452,7 +453,7 @@ mod tests { }]), total_rewards, dec!(0.00001), - epoch(), + reward_info, ); let promo_rewards = sp_infos.iter_rewards().only_promotion_rewards(); @@ -467,6 +468,7 @@ mod tests { #[test] fn single_sp_unallocated_more_than_matched_promotion() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // 1,000 unallocated let total_rewards = dec!(11_000); let sp_session = dec!(1000); @@ -491,7 +493,7 @@ mod tests { }]), total_rewards, dec!(0.00001), - epoch(), + reward_info, ); let promo_rewards = sp_infos.iter_rewards().only_promotion_rewards(); @@ -506,6 +508,7 @@ mod tests { #[test] fn unallocated_matching_does_not_exceed_promotion() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // 100 unallocated let total_rewards = dec!(1100); let sp_session = dec!(1000); @@ -530,7 +533,7 @@ mod tests { }]), total_rewards, dec!(0.00001), - epoch(), + reward_info, ); let promo_rewards = sp_infos.iter_rewards().only_promotion_rewards(); @@ -545,6 +548,7 @@ mod tests { #[test] fn no_matched_promotions_full_bucket_allocation() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // The service providers DC session represents _more_ than the // available amount of sp_rewards for an epoch. // No matching on promotions should occur. @@ -564,7 +568,7 @@ mod tests { }]), total_rewards, dec!(629) / dec!(1_000_000) / dec!(1_000_000), - epoch(), + reward_info, ); let (promo_1, sp_1) = sp_infos.single_sp_rewards(0); @@ -582,6 +586,7 @@ mod tests { #[test] fn no_matched_promotions_multiple_sp_full_bucket_allocation() { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // The Service Providers DC sessions far surpass the // available amount of sp_rewards for an epoch. // No matching on promotions should occur. @@ -612,7 +617,7 @@ mod tests { ]), total_rewards, dec!(629) / dec!(1_000_000) / dec!(1_000_000), - epoch(), + reward_info, ); let sp_base_reward = dec!(4_109_589_041_095.50); @@ -648,6 +653,7 @@ mod tests { assert_eq!(unallocated, 2); } + use crate::service_provider::default_rewards_info; use proptest::prelude::*; prop_compose! { @@ -694,12 +700,13 @@ mod tests { total_allocation in any::().prop_map(Decimal::from) ) { + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from([(0, dc_session)]), ServiceProviderPromotions::from(promotions), total_allocation, dec!(0.00001), - epoch() + reward_info, ); let total_perc= sp_infos.total_percent(); @@ -719,15 +726,15 @@ mod tests { promotions in prop::collection::vec(arb_sp_promotion(), 0..10), mobile_bone_price in 1..5000 ) { - let epoch = epoch(); - let total_allocation = service_provider::get_scheduled_tokens(&epoch); + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let total_allocation = service_provider::get_scheduled_tokens(reward_info.epoch_emissions); let sp_infos = ServiceProviderRewardInfos::new( ServiceProviderDCSessions::from(dc_sessions), ServiceProviderPromotions::from(promotions), total_allocation, Decimal::from(mobile_bone_price) / dec!(1_000_000) / dec!(1_000_000), - epoch + reward_info, ); // NOTE: This can be a sanity check when debugging. There are cases @@ -803,7 +810,7 @@ mod tests { for info in self.coll.iter() { if info.sp_id == sp_id { return info - .iter_rewards(self.total_sp_allocation, &self.reward_epoch) + .iter_rewards(self.total_sp_allocation, &self.reward_info) .into_iter() .map(|(_, x)| x) .collect(); diff --git a/mobile_verifier/src/telemetry.rs b/mobile_verifier/src/telemetry.rs index 224fc3ab3..e213790d2 100644 --- a/mobile_verifier/src/telemetry.rs +++ b/mobile_verifier/src/telemetry.rs @@ -1,14 +1,15 @@ +use crate::rewarder; use chrono::{DateTime, Utc}; +use mobile_config::EpochPeriod; use sqlx::{Pool, Postgres}; -use crate::rewarder; - const LAST_REWARDED_END_TIME: &str = "last_rewarded_end_time"; const DATA_TRANSFER_REWARDS_SCALE: &str = "data_transfer_rewards_scale"; pub async fn initialize(db: &Pool) -> anyhow::Result<()> { - last_rewarded_end_time(rewarder::last_rewarded_end_time(db).await?); - + let next_reward_epoch = rewarder::next_reward_epoch(db).await?; + let epoch_period: EpochPeriod = next_reward_epoch.try_into()?; + last_rewarded_end_time(epoch_period.period.start); Ok(()) } diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 7e1563929..6f689e6ba 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -1,4 +1,4 @@ -use chrono::{DateTime, Utc}; +use chrono::{DateTime, Duration, Utc}; use file_store::{ file_sink::{FileSinkClient, Message as SinkMessage}, traits::TimestampEncode, @@ -23,6 +23,8 @@ use mobile_config::{ }, }; +use mobile_config::client::sub_dao_client::SubDaoEpochRewardInfoResolver; +use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; use mobile_verifier::{ boosting_oracles::AssignedCoverageObjects, GatewayResolution, GatewayResolver, }; @@ -33,12 +35,20 @@ use std::{collections::HashMap, str::FromStr}; use tokio::{sync::mpsc::error::TryRecvError, time::timeout}; use tonic::async_trait; +pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; +pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + #[derive(Debug, Clone)] #[allow(dead_code)] pub struct MockHexBoostingClient { boosted_hexes: Vec, } +#[derive(Debug, Clone)] +pub struct MockSubDaoRewardsClient { + info: Option, +} + impl MockHexBoostingClient { pub fn new(boosted_hexes: Vec) -> Self { Self { boosted_hexes } @@ -61,6 +71,18 @@ impl HexBoostingInfoResolver for MockHexBoostingClient { } } +#[async_trait::async_trait] +impl SubDaoEpochRewardInfoResolver for MockSubDaoRewardsClient { + type Error = ClientError; + + async fn resolve_info( + &self, + _sub_dao: &PublicKeyBinary, + _epoch: u64, + ) -> Result, Self::Error> { + Ok(self.info.clone()) + } +} pub struct MockFileSinkReceiver { pub receiver: tokio::sync::mpsc::Receiver>, } @@ -369,3 +391,18 @@ impl GatewayResolver for GatewayClientAllOwnersValid { Ok(GatewayResolution::AssertedLocation(0x8c2681a3064d9ff)) } } + +pub fn default_rewards_info( + total_emissions: u64, + epoch_duration: Duration, +) -> ResolvedSubDaoEpochRewardInfo { + let now = Utc::now(); + ResolvedSubDaoEpochRewardInfo { + epoch: 1, + epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_period: (now - epoch_duration)..now, + epoch_emissions: Decimal::from(total_emissions), + rewards_issued_at: now, + } +} diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index ae11f4363..4af9f9d7b 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -1,4 +1,6 @@ -use crate::common::{self, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext}; +use crate::common::{ + self, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext, +}; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ coverage::{CoverageObject as FSCoverageObject, KeyType, RadioHexSignalLevel}, @@ -53,17 +55,17 @@ async fn update_assignments(pool: &PgPool) -> anyhow::Result<()> { async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; - let epoch_duration = epoch.end - epoch.start; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; // seed HBs where we have a coverage reports for a singluar hex location per radio - seed_heartbeats_v1(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_heartbeats_v1(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; @@ -74,7 +76,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { NonZeroU32::new(15).unwrap(), NonZeroU32::new(35).unwrap(), ]; - let start_ts_1 = epoch.start - boost_period_length; + let start_ts_1 = reward_info.epoch_period.start - boost_period_length; let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where reward start time is in the third & last period length @@ -83,7 +85,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { NonZeroU32::new(10).unwrap(), NonZeroU32::new(20).unwrap(), ]; - let start_ts_2 = epoch.start - (boost_period_length * 2); + let start_ts_2 = reward_info.epoch_period.start - (boost_period_length * 2); let end_ts_2 = start_ts_2 + (boost_period_length * multipliers2.len() as i32); // setup boosted hex where no start or end time is set @@ -133,9 +135,10 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration) - .to_u64() - .unwrap(); + let total_poc_emissions = + reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -144,7 +147,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_maybe_unallocated( @@ -180,7 +183,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { ); // Calculating expected rewards - let (regular_poc, boosted_poc) = get_poc_allocation_buckets(epoch_duration); + let (regular_poc, boosted_poc) = get_poc_allocation_buckets(reward_info.epoch_emissions); // With regular poc now 50% of total emissions, that will be split // between the 3 radios equally. 900 comes from IndoorWifi 400 * @@ -227,8 +230,8 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { assert_eq!(total_poc_emissions, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); @@ -321,6 +324,8 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -328,7 +333,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards(&mut mobile_rewards) @@ -365,14 +370,13 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let unallocated_sum: u64 = unallocated_reward.amount; let total = poc_sum + unallocated_sum; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); } else { @@ -386,17 +390,16 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; - let epoch_duration = epoch.end - epoch.start; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; // seed HBs where we have multiple coverage reports for one radio and one report for the others - seed_heartbeats_v2(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_heartbeats_v2(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; @@ -407,7 +410,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res NonZeroU32::new(15).unwrap(), NonZeroU32::new(35).unwrap(), ]; - let start_ts_1 = epoch.start - boost_period_length; + let start_ts_1 = reward_info.epoch_period.start - boost_period_length; let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where reward start time is in the third & last period length @@ -417,7 +420,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res NonZeroU32::new(20).unwrap(), ]; - let start_ts_2 = epoch.start - (boost_period_length * 2); + let start_ts_2 = reward_info.epoch_period.start - (boost_period_length * 2); let end_ts_2 = start_ts_2 + (boost_period_length * multipliers2.len() as i32); // setup boosted hex where reward start time is in the first period length @@ -428,7 +431,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res NonZeroU32::new(20).unwrap(), ]; - let start_ts_3 = epoch.start; + let start_ts_3 = reward_info.epoch_period.start; let end_ts_3 = start_ts_3 + (boost_period_length * multipliers3.len() as i32); let boosted_hexes = vec![ @@ -478,9 +481,10 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res }, ]; - let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration) - .to_u64() - .unwrap(); + let total_poc_emissions = + reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); let (_, rewards) = tokio::join!( @@ -490,7 +494,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_maybe_unallocated( @@ -530,7 +534,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res // - 2 covered hexes boosted at 10x // - 1 covered hex boosted at 20x // - 1 covered hex no boost - let (regular_poc, boosted_poc) = get_poc_allocation_buckets(epoch_duration); + let (regular_poc, boosted_poc) = get_poc_allocation_buckets(reward_info.epoch_emissions); // With regular poc now 50% of total emissions, that will be split // between the 3 radios equally. @@ -589,8 +593,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res assert_eq!(total_poc_emissions, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); @@ -602,15 +605,14 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; - seed_heartbeats_v1(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_heartbeats_v1(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; @@ -620,8 +622,8 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { NonZeroU32::new(10).unwrap(), NonZeroU32::new(15).unwrap(), ]; - let start_ts_1 = - epoch.start - (boost_period_length * multipliers1.len() as i32 + ChronoDuration::days(1)); + let start_ts_1 = reward_info.epoch_period.start + - (boost_period_length * multipliers1.len() as i32 + ChronoDuration::days(1)); let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where reward start time is same as the boost period ends @@ -630,7 +632,8 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { NonZeroU32::new(12).unwrap(), NonZeroU32::new(17).unwrap(), ]; - let start_ts_2 = epoch.start - (boost_period_length * multipliers2.len() as i32); + let start_ts_2 = + reward_info.epoch_period.start - (boost_period_length * multipliers2.len() as i32); let end_ts_2 = start_ts_2 + (boost_period_length * multipliers2.len() as i32); let boosted_hexes = vec![ @@ -665,7 +668,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards(&mut mobile_rewards) @@ -703,14 +706,13 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let unallocated_sum: u64 = unallocated_reward.amount; let total = poc_sum + unallocated_sum; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); } else { @@ -723,15 +725,14 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; - let epoch_duration = epoch.end - epoch.start; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; seed_heartbeats_with_location_trust( - epoch.start, + reward_info.epoch_period.start, &mut txn, HotspotLocationTrust { meters: 10, @@ -747,14 +748,14 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: }, ) .await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; // setup boosted hex where reward start time is in the second period length let multipliers1 = vec![NonZeroU32::new(2).unwrap()]; - let start_ts_1 = epoch.start; + let start_ts_1 = reward_info.epoch_period.start; let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where no start or end time is set @@ -786,9 +787,10 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: ]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration) - .to_u64() - .unwrap(); + let total_poc_emissions = + reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -797,7 +799,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_maybe_unallocated( @@ -833,7 +835,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: ); // Calculating expected rewards - let (regular_poc, boosted_poc) = get_poc_allocation_buckets(epoch_duration); + let (regular_poc, boosted_poc) = get_poc_allocation_buckets(reward_info.epoch_emissions); // Here's how we get the regular shares per coverage points // | base coverage point | speedtest | location | total | @@ -880,14 +882,13 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: hotspot_1.total_poc_reward() + hotspot_2.total_poc_reward() + hotspot_3.total_poc_reward(); let total = poc_sum + unallocated_reward.amount; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); @@ -900,15 +901,14 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( ) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; - let epoch_duration = epoch.end - epoch.start; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; seed_heartbeats_with_location_trust( - epoch.start, + reward_info.epoch_period.start, &mut txn, // hotspot 1 can receive boosting HotspotLocationTrust { @@ -927,14 +927,14 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( }, ) .await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; // setup boosted hex where reward start time is in the second period length let multipliers1 = vec![NonZeroU32::new(2).unwrap()]; - let start_ts_1 = epoch.start; + let start_ts_1 = reward_info.epoch_period.start; let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where no start or end time is set @@ -966,9 +966,10 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( ]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration) - .to_u64() - .unwrap(); + let total_poc_emissions = + reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -977,7 +978,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_maybe_unallocated( @@ -1013,7 +1014,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( ); // Calculating expected rewards - let (regular_poc, boosted_poc) = get_poc_allocation_buckets(epoch_duration); + let (regular_poc, boosted_poc) = get_poc_allocation_buckets(reward_info.epoch_emissions); // Here's how we get the regular shares per coverage points // | base coverage point | speedtest | location | total | @@ -1060,14 +1061,13 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( hotspot_1.total_poc_reward() + hotspot_2.total_poc_reward() + hotspot_3.total_poc_reward(); let total = poc_sum + unallocated_reward.amount; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); @@ -1079,18 +1079,17 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; - let epoch_duration = epoch.end - epoch.start; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let boost_period_length = Duration::days(30); // seed all the things let mut txn = pool.clone().begin().await?; // seed HBs where we have multiple coverage reports for one radio and one report for the others // include a cbrs radio alongside 2 wifi radios - seed_heartbeats_v4(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_radio_thresholds(epoch.start, &mut txn).await?; + seed_heartbeats_v4(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_radio_thresholds(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; @@ -1101,7 +1100,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an NonZeroU32::new(15).unwrap(), NonZeroU32::new(35).unwrap(), ]; - let start_ts_1 = epoch.start - boost_period_length; + let start_ts_1 = reward_info.epoch_period.start - boost_period_length; let end_ts_1 = start_ts_1 + (boost_period_length * multipliers1.len() as i32); // setup boosted hex where reward start time is in the third & last period length @@ -1110,7 +1109,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an NonZeroU32::new(10).unwrap(), NonZeroU32::new(20).unwrap(), ]; - let start_ts_2 = epoch.start - (boost_period_length * 2); + let start_ts_2 = reward_info.epoch_period.start - (boost_period_length * 2); let end_ts_2 = start_ts_2 + (boost_period_length * multipliers2.len() as i32); // setup boosted hex where reward start time is in the first period length @@ -1120,7 +1119,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an NonZeroU32::new(10).unwrap(), NonZeroU32::new(20).unwrap(), ]; - let start_ts_3 = epoch.start; + let start_ts_3 = reward_info.epoch_period.start; let end_ts_3 = start_ts_3 + (boost_period_length * multipliers3.len() as i32); let boosted_hexes = vec![ @@ -1171,9 +1170,10 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an ]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let total_poc_emissions = reward_shares::get_scheduled_tokens_for_poc(epoch_duration) - .to_u64() - .unwrap(); + let total_poc_emissions = + reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1182,7 +1182,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_maybe_unallocated( @@ -1217,7 +1217,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an ); // Calculating expected rewards - let (regular_poc, boosted_poc) = get_poc_allocation_buckets(epoch_duration); + let (regular_poc, boosted_poc) = get_poc_allocation_buckets(reward_info.epoch_emissions); // Here's how we get the regular shares per coverage points // | base coverage point | speedtest | location | total | @@ -1273,14 +1273,13 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an hotspot_1.total_poc_reward() + hotspot_2.total_poc_reward() + hotspot_3.total_poc_reward(); let total = poc_sum + unallocated_reward.amount; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); @@ -1888,10 +1887,9 @@ async fn save_seniority_object( Ok(()) } -fn get_poc_allocation_buckets(epoch_duration: Duration) -> (Decimal, Decimal) { +fn get_poc_allocation_buckets(total_emissions: Decimal) -> (Decimal, Decimal) { // To not deal with percentages of percentages, let's start with the // total emissions and work from there. - let total_emissions = reward_shares::get_total_scheduled_tokens(epoch_duration); let data_transfer = total_emissions * dec!(0.4); let regular_poc = total_emissions * dec!(0.1); let boosted_poc = total_emissions * dec!(0.1); diff --git a/mobile_verifier/tests/integrations/rewarder_mappers.rs b/mobile_verifier/tests/integrations/rewarder_mappers.rs index 2a74bae73..a7883da6c 100644 --- a/mobile_verifier/tests/integrations/rewarder_mappers.rs +++ b/mobile_verifier/tests/integrations/rewarder_mappers.rs @@ -1,5 +1,5 @@ -use crate::common::{self, MockFileSinkReceiver}; -use chrono::{DateTime, Duration as ChronoDuration, Utc}; +use crate::common::{self, default_rewards_info, MockFileSinkReceiver}; +use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ mobile_subscriber::{SubscriberLocationIngestReport, SubscriberLocationReq}, subscriber_verified_mapping_event::SubscriberVerifiedMappingEvent, @@ -28,16 +28,16 @@ const HOTSPOT_1: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; #[sqlx::test] async fn test_mapper_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // seed db let mut txn = pool.clone().begin().await?; - seed_mapping_data(epoch.end, &mut txn).await?; + seed_mapping_data(reward_info.epoch_period.end, &mut txn).await?; txn.commit().await.expect("db txn failed"); let (_, rewards) = tokio::join!( - rewarder::reward_mappers(&pool, &mobile_rewards_client, &epoch), + rewarder::reward_mappers(&pool, &mobile_rewards_client, &reward_info), receive_expected_rewards(&mut mobile_rewards) ); @@ -82,9 +82,10 @@ async fn test_mapper_rewards(pool: PgPool) -> anyhow::Result<()> { assert_eq!(1, unallocated_reward.amount); // confirm the total rewards allocated matches expectations - let expected_sum = reward_shares::get_scheduled_tokens_for_mappers(epoch.end - epoch.start) - .to_u64() - .unwrap(); + let expected_sum = + reward_shares::get_scheduled_tokens_for_mappers(reward_info.epoch_emissions) + .to_u64() + .unwrap(); let subscriber_sum = subscriber_rewards[0].discovery_location_amount + subscriber_rewards[1].discovery_location_amount + subscriber_rewards[2].discovery_location_amount @@ -92,8 +93,7 @@ async fn test_mapper_rewards(pool: PgPool) -> anyhow::Result<()> { assert_eq!(expected_sum, subscriber_sum); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(subscriber_sum) / daily_total) + let percent = (Decimal::from(subscriber_sum) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.2)); } else { @@ -107,26 +107,26 @@ async fn test_subscriber_can_only_earn_verification_mapping_if_earned_disco_mapp pool: PgPool, ) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let mut txn = pool.begin().await?; let sub_loc_report = SubscriberLocationIngestReport { - received_timestamp: epoch.end - ChronoDuration::hours(1), + received_timestamp: reward_info.epoch_period.end - ChronoDuration::hours(1), report: SubscriberLocationReq { subscriber_id: SUBSCRIBER_1.to_string().encode_to_vec(), - timestamp: epoch.end - ChronoDuration::hours(1), + timestamp: reward_info.epoch_period.end - ChronoDuration::hours(1), carrier_pub_key: PublicKeyBinary::from_str(HOTSPOT_1).unwrap(), }, }; subscriber_location::save(&sub_loc_report, &mut txn).await?; let vme_report = SubscriberVerifiedMappingEventIngestReport { - received_timestamp: epoch.end - ChronoDuration::hours(1), + received_timestamp: reward_info.epoch_period.end - ChronoDuration::hours(1), report: SubscriberVerifiedMappingEvent { subscriber_id: SUBSCRIBER_2.to_string().encode_to_vec(), total_reward_points: 50, - timestamp: epoch.end - ChronoDuration::hours(1), + timestamp: reward_info.epoch_period.end - ChronoDuration::hours(1), carrier_mapping_key: PublicKeyBinary::from_str(HOTSPOT_1).unwrap(), }, }; @@ -135,13 +135,13 @@ async fn test_subscriber_can_only_earn_verification_mapping_if_earned_disco_mapp txn.commit().await?; let (_, rewards) = tokio::join!( - rewarder::reward_mappers(&pool, &mobile_rewards_client, &epoch), + rewarder::reward_mappers(&pool, &mobile_rewards_client, &reward_info), mobile_rewards.receive_subscriber_reward() ); mobile_rewards.assert_no_messages(); - let total_pool = reward_shares::get_scheduled_tokens_for_mappers(epoch.end - epoch.start); + let total_pool = reward_shares::get_scheduled_tokens_for_mappers(reward_info.epoch_emissions); assert_eq!( rewards.discovery_location_amount + rewards.verification_mapping_amount, total_pool.to_u64().unwrap() diff --git a/mobile_verifier/tests/integrations/rewarder_oracles.rs b/mobile_verifier/tests/integrations/rewarder_oracles.rs index 2830afe2e..0da4a61c4 100644 --- a/mobile_verifier/tests/integrations/rewarder_oracles.rs +++ b/mobile_verifier/tests/integrations/rewarder_oracles.rs @@ -1,5 +1,5 @@ -use crate::common::{self, MockFileSinkReceiver}; -use chrono::{Duration as ChronoDuration, Utc}; +use crate::common::{self, default_rewards_info, MockFileSinkReceiver}; +use chrono::Duration; use helium_proto::services::poc_mobile::{ MobileRewardShare, UnallocatedReward, UnallocatedRewardType, }; @@ -11,12 +11,12 @@ use sqlx::PgPool; #[sqlx::test] async fn test_oracle_rewards(_pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let (_, rewards) = tokio::join!( // run rewards for oracles - rewarder::reward_oracles(&mobile_rewards_client, &epoch), + rewarder::reward_oracles(&mobile_rewards_client, &reward_info), receive_expected_rewards(&mut mobile_rewards) ); if let Ok(unallocated_reward) = rewards { @@ -28,14 +28,14 @@ async fn test_oracle_rewards(_pool: PgPool) -> anyhow::Result<()> { assert_eq!(3_287_671_232_876, unallocated_reward.amount); // confirm the total rewards allocated matches expectations - let expected_sum = reward_shares::get_scheduled_tokens_for_oracles(epoch.end - epoch.start) - .to_u64() - .unwrap(); + let expected_sum = + reward_shares::get_scheduled_tokens_for_oracles(reward_info.epoch_emissions) + .to_u64() + .unwrap(); assert_eq!(expected_sum, unallocated_reward.amount); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(unallocated_reward.amount) / daily_total) + let percent = (Decimal::from(unallocated_reward.amount) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.04)); } else { diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index 7265cef8e..e7d59f855 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -1,6 +1,8 @@ use std::ops::Range; -use crate::common::{self, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext}; +use crate::common::{ + self, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext, +}; use chrono::{DateTime, Duration as ChronoDuration, Utc}; use file_store::{ coverage::{CoverageObject as FSCoverageObject, KeyType, RadioHexSignalLevel}, @@ -44,14 +46,14 @@ const PAYER_1: &str = "11eX55faMbqZB7jzN4p67m6w7ScPMH6ubnvCjCPLh72J49PaJEL"; async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // seed all the things let mut txn = pool.clone().begin().await?; - seed_heartbeats(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_data_sessions(epoch.start, &mut txn).await?; + seed_heartbeats(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_data_sessions(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments(&pool).await?; @@ -66,7 +68,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, + &reward_info, dec!(0.0001) ), receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 3, false) @@ -121,14 +123,13 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let dc_sum: u64 = dc_rewards.iter().map(|r| r.dc_transfer_reward).sum(); let total = poc_sum + dc_sum; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(total) / daily_total) + let percent = (Decimal::from(total) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.6)); } else { diff --git a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs index 23d343fda..edaeddf2e 100644 --- a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs +++ b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::string::ToString; use async_trait::async_trait; -use chrono::{DateTime, Duration as ChronoDuration, Utc}; +use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use helium_proto::{ service_provider_promotions::Promotion, services::poc_mobile::{ @@ -14,7 +14,7 @@ use rust_decimal::prelude::*; use rust_decimal_macros::dec; use sqlx::{PgPool, Postgres, Transaction}; -use crate::common::{self, MockFileSinkReceiver}; +use crate::common::{self, default_rewards_info, MockFileSinkReceiver}; use mobile_config::client::{carrier_service_client::CarrierServiceVerifier, ClientError}; use mobile_verifier::{data_session, reward_shares, rewarder, service_provider}; @@ -75,17 +75,18 @@ async fn test_service_provider_rewards(pool: PgPool) -> anyhow::Result<()> { let carrier_client = MockCarrierServiceClient::new(valid_sps); let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // seed db with test specific data let mut txn = pool.clone().begin().await?; - seed_hotspot_data(epoch.end, &mut txn).await?; + seed_hotspot_data(reward_info.epoch_period.end, &mut txn).await?; txn.commit().await?; - let dc_sessions = service_provider::get_dc_sessions(&pool, &carrier_client, &epoch).await?; + let dc_sessions = + service_provider::get_dc_sessions(&pool, &carrier_client, &reward_info.epoch_period) + .await?; let sp_promotions = carrier_client - .list_incentive_promotions(&epoch.start) + .list_incentive_promotions(&reward_info.epoch_period.start) .await?; let (_, rewards) = tokio::join!( @@ -93,7 +94,7 @@ async fn test_service_provider_rewards(pool: PgPool) -> anyhow::Result<()> { dc_sessions, sp_promotions.into(), &mobile_rewards_client, - &epoch, + &reward_info, dec!(0.0001), ), receive_expected_rewards(&mut mobile_rewards) @@ -115,14 +116,13 @@ async fn test_service_provider_rewards(pool: PgPool) -> anyhow::Result<()> { // confirm the total rewards allocated matches expectations let expected_sum = - reward_shares::get_scheduled_tokens_for_service_providers(epoch.end - epoch.start) + reward_shares::get_scheduled_tokens_for_service_providers(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, sp_reward.amount + unallocated_reward.amount); // confirm the rewarded percentage amount matches expectations - let daily_total = reward_shares::get_total_scheduled_tokens(epoch.end - epoch.start); - let percent = (Decimal::from(unallocated_reward.amount) / daily_total) + let percent = (Decimal::from(unallocated_reward.amount) / reward_info.epoch_emissions) .round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); assert_eq!(percent, dec!(0.1)); } else { @@ -140,14 +140,14 @@ async fn test_service_provider_rewards_halt_on_invalid_sp(pool: PgPool) -> anyho valid_sps.insert(PAYER_1.to_string(), SP_1.to_string()); let carrier_client = MockCarrierServiceClient::new(valid_sps); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); let mut txn = pool.clone().begin().await?; - seed_hotspot_data_invalid_sp(epoch.end, &mut txn).await?; + seed_hotspot_data_invalid_sp(reward_info.epoch_period.end, &mut txn).await?; txn.commit().await.expect("db txn failed"); - let dc_sessions = service_provider::get_dc_sessions(&pool, &carrier_client, &epoch).await; + let dc_sessions = + service_provider::get_dc_sessions(&pool, &carrier_client, &reward_info.epoch_period).await; assert_eq!( dc_sessions.unwrap_err().to_string(), format!("unknown service provider {PAYER_2}") @@ -187,18 +187,20 @@ async fn test_service_provider_promotion_rewards(pool: PgPool) -> anyhow::Result ], }]); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let mut txn = pool.begin().await?; - seed_hotspot_data(epoch.end, &mut txn).await?; // DC transferred == 6,000 reward amount + seed_hotspot_data(reward_info.epoch_period.end, &mut txn).await?; // DC transferred == 6,000 reward amount txn.commit().await?; - let dc_sessions = service_provider::get_dc_sessions(&pool, &carrier_client, &epoch).await?; + let dc_sessions = + service_provider::get_dc_sessions(&pool, &carrier_client, &reward_info.epoch_period) + .await?; let sp_promotions = carrier_client - .list_incentive_promotions(&epoch.start) + .list_incentive_promotions(&reward_info.epoch_period.start) .await?; let (_, rewards) = tokio::join!( @@ -206,7 +208,7 @@ async fn test_service_provider_promotion_rewards(pool: PgPool) -> anyhow::Result dc_sessions, sp_promotions.into(), &mobile_rewards_client, - &epoch, + &reward_info, dec!(0.00001) ), async move { @@ -233,25 +235,26 @@ async fn test_service_provider_promotion_rewards(pool: PgPool) -> anyhow::Result let promo_reward_3 = promos[2].clone(); // 1 share - assert_eq!(promo_reward_1.service_provider_amount, 1_500); - assert_eq!(promo_reward_1.matched_amount, 1_500); + assert_eq!(promo_reward_1.service_provider_amount, 1_499); + assert_eq!(promo_reward_1.matched_amount, 1_499); // 2 shares - assert_eq!(promo_reward_2.service_provider_amount, 3_000); - assert_eq!(promo_reward_2.matched_amount, 3_000); + assert_eq!(promo_reward_2.service_provider_amount, 2999); + assert_eq!(promo_reward_2.matched_amount, 2999); // 3 shares - assert_eq!(promo_reward_3.service_provider_amount, 4_500); - assert_eq!(promo_reward_3.matched_amount, 4_500); + assert_eq!(promo_reward_3.service_provider_amount, 4_499); + assert_eq!(promo_reward_3.matched_amount, 4_499); // dc_percentage * total_sp_allocation rounded down assert_eq!(sp_reward.amount, 50_999); - let unallocated_sp_rewards = get_unallocated_sp_rewards(&epoch); + let unallocated_sp_rewards = get_unallocated_sp_rewards(reward_info.epoch_emissions); let expected_unallocated = unallocated_sp_rewards - 50_999 // 85% service provider rewards rounded down - - 9_000 // 15% service provider promotions - - 9_000; // matched promotion + - 8_998 // 15% service provider promotions + - 8_998 // matched promotion + + 2; // unexpected rounding - TODO investigate assert_eq!(unallocated.amount, expected_unallocated); @@ -331,8 +334,8 @@ async fn seed_hotspot_data_invalid_sp( } // Helper for turning Decimal -> u64 to compare against output rewards -fn get_unallocated_sp_rewards(epoch: &std::ops::Range>) -> u64 { - reward_shares::get_scheduled_tokens_for_service_providers(epoch.end - epoch.start) +fn get_unallocated_sp_rewards(total_emissions: Decimal) -> u64 { + reward_shares::get_scheduled_tokens_for_service_providers(total_emissions) .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0) diff --git a/mobile_verifier/tests/integrations/subscriber_verified_mapping_event.rs b/mobile_verifier/tests/integrations/subscriber_verified_mapping_event.rs index f002b192d..1b9b77516 100644 --- a/mobile_verifier/tests/integrations/subscriber_verified_mapping_event.rs +++ b/mobile_verifier/tests/integrations/subscriber_verified_mapping_event.rs @@ -217,7 +217,7 @@ async fn select_events( ) -> anyhow::Result> { let rows = sqlx::query( r#" - SELECT + SELECT subscriber_id, total_reward_points, received_timestamp diff --git a/reward_scheduler/src/lib.rs b/reward_scheduler/src/lib.rs index 788f4eb79..a2aebbac0 100644 --- a/reward_scheduler/src/lib.rs +++ b/reward_scheduler/src/lib.rs @@ -3,9 +3,9 @@ use std::{ops::Range, time::Duration}; #[derive(Debug)] pub struct Scheduler { - pub reward_period_length: Duration, - pub reward_period: Range>, - pub reward_offset: Duration, + pub period_duration: Duration, + pub schedule_period: Range>, + pub period_offset: Duration, } #[derive(thiserror::Error, Debug)] @@ -14,38 +14,38 @@ pub struct OutOfRangeError; impl Scheduler { pub fn new( - reward_period_length: Duration, - last_rewarded_end_time: DateTime, - next_rewarded_end_time: DateTime, - reward_offset: Duration, + period_duration: Duration, + schedule_start_time: DateTime, + schedule_end_time: DateTime, + period_offset: Duration, ) -> Self { Self { - reward_period_length, - reward_period: last_rewarded_end_time..next_rewarded_end_time, - reward_offset, + period_duration, + schedule_period: schedule_start_time..schedule_end_time, + period_offset, } } - pub fn should_reward(&self, now: DateTime) -> bool { - now >= self.reward_period.end + self.reward_offset + pub fn should_trigger(&self, now: DateTime) -> bool { + now >= self.schedule_period.end + self.period_offset } - pub fn next_reward_period(&self) -> Range> { - self.reward_period.end..(self.reward_period.end + self.reward_period_length) + pub fn next_trigger_period(&self) -> Range> { + self.schedule_period.end..(self.schedule_period.end + self.period_duration) } pub fn sleep_duration( &self, now: DateTime, ) -> Result { - let next_reward_period = self.next_reward_period(); + let next_period = self.next_trigger_period(); - let duration = if self.reward_period.end + self.reward_offset > now { - self.reward_period.end + self.reward_offset - now - } else if next_reward_period.end + self.reward_offset <= now { + let duration = if self.schedule_period.end + self.period_offset > now { + self.schedule_period.end + self.period_offset - now + } else if next_period.end + self.period_offset <= now { chrono::Duration::zero() } else { - (next_reward_period.end + self.reward_offset) - now + (next_period.end + self.period_offset) - now }; duration.to_std().map_err(|_| OutOfRangeError) @@ -62,7 +62,7 @@ mod tests { Utc.with_ymd_and_hms(y, m, d, h, min, s).unwrap() } - fn reward_period_length() -> Duration { + fn period_length() -> Duration { chrono::Duration::hours(24).to_std().unwrap() } @@ -75,7 +75,7 @@ mod tests { #[test] fn boot_mid_period_with_no_reward() { let scheduler = Scheduler::new( - reward_period_length(), + period_length(), dt(2022, 12, 1, 0, 0, 0), dt(2022, 12, 2, 0, 0, 0), chrono::Duration::minutes(30).to_std().unwrap(), @@ -83,7 +83,7 @@ mod tests { let now = dt(2022, 12, 1, 1, 0, 0); - assert!(!scheduler.should_reward(now)); + assert!(!scheduler.should_trigger(now)); assert_eq!( standard_duration(1410).unwrap(), scheduler @@ -95,7 +95,7 @@ mod tests { #[test] fn reward_after_period() { let scheduler = Scheduler::new( - reward_period_length(), + period_length(), dt(2022, 12, 1, 0, 0, 0), dt(2022, 12, 2, 0, 0, 0), chrono::Duration::minutes(30).to_std().unwrap(), @@ -105,9 +105,9 @@ mod tests { assert_eq!( dt(2022, 12, 1, 0, 0, 0)..dt(2022, 12, 2, 0, 0, 0), - scheduler.reward_period + scheduler.schedule_period ); - assert!(scheduler.should_reward(now)); + assert!(scheduler.should_trigger(now)); assert_eq!( standard_duration(1440).unwrap(), scheduler @@ -117,9 +117,9 @@ mod tests { } #[test] - fn check_after_reward_period_but_before_offset() { + fn check_after_trigger_period_but_before_offset() { let scheduler = Scheduler::new( - reward_period_length(), + period_length(), dt(2022, 12, 1, 0, 0, 0), dt(2022, 12, 2, 0, 0, 0), chrono::Duration::minutes(30).to_std().unwrap(), @@ -129,9 +129,9 @@ mod tests { assert_eq!( dt(2022, 12, 1, 0, 0, 0)..dt(2022, 12, 2, 0, 0, 0), - scheduler.reward_period + scheduler.schedule_period ); - assert!(!scheduler.should_reward(now)); + assert!(!scheduler.should_trigger(now)); assert_eq!( standard_duration(15).unwrap(), scheduler From 2510c95e01216c9eddb783fb4c6068704263477a Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 19 Nov 2024 13:31:24 +0000 Subject: [PATCH 02/36] tidy up --- mobile_config/src/client/sub_dao_client.rs | 6 +++-- mobile_verifier/src/cli/reward_from_db.rs | 5 ++-- mobile_verifier/src/reward_shares.rs | 2 +- mobile_verifier/src/service_provider/mod.rs | 24 +------------------ .../src/service_provider/reward.rs | 21 +++++++++++++++- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index 7606c7ffa..628e015cc 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -2,9 +2,11 @@ use super::{call_with_retry, ClientError, Settings}; use crate::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; use file_store::traits::MsgVerify; use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; -use helium_proto::services::mobile_config::SubDaoEpochRewardInfoReqV1; use helium_proto::{ - services::{mobile_config, Channel}, + services::{ + mobile_config::{self, SubDaoEpochRewardInfoReqV1}, + Channel, + }, Message, }; use std::{error::Error, sync::Arc, time::Duration}; diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index 6dbb69256..c623319af 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -31,7 +31,7 @@ impl Cmd { let reward_epoch = self.reward_epoch; - let sub_dao_pubkey = PublicKeyBinary::from_str(&MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; + let sub_dao_pubkey = PublicKeyBinary::from_str(MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; let sub_dao_rewards_client = SubDaoClient::from_settings(&settings.config_client)?; let reward_info = sub_dao_rewards_client .resolve_info(&sub_dao_pubkey, reward_epoch) @@ -56,7 +56,8 @@ impl Cmd { SpeedtestAverages::aggregate_epoch_averages(reward_info.epoch_period.end, &pool) .await?; - let unique_connections = unique_connections::db::get(&pool, &epoch).await?; + let unique_connections = + unique_connections::db::get(&pool, &reward_info.epoch_period).await?; let reward_shares = CoverageShares::new( &pool, diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 474157e7a..36ca36e91 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -2545,7 +2545,7 @@ mod test { .round_dp_with_strategy(0, RoundingStrategy::ToZero) .to_u64() .unwrap_or(0); - assert_eq!(unallocated_sp_reward_amount, 490_00_000_000_000_000); + assert_eq!(unallocated_sp_reward_amount, 49_000_000_000_000_000); } #[test] diff --git a/mobile_verifier/src/service_provider/mod.rs b/mobile_verifier/src/service_provider/mod.rs index e45b4e15d..ac0670aaa 100644 --- a/mobile_verifier/src/service_provider/mod.rs +++ b/mobile_verifier/src/service_provider/mod.rs @@ -1,39 +1,17 @@ -use chrono::{Duration, Utc}; pub use dc_sessions::{get_dc_sessions, ServiceProviderDCSessions}; -use helium_crypto::PublicKeyBinary; -use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; pub use promotions::{get_promotions, ServiceProviderPromotions}; pub use reward::ServiceProviderRewardInfos; use rust_decimal::Decimal; -use std::str::FromStr; mod dc_sessions; mod promotions; mod reward; -pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; -pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; - // This type is used in lieu of the helium_proto::ServiceProvider enum so we can // handle more than a single value without adding a hard deploy dependency to // mobile-verifier when a new carrier is added.. pub type ServiceProviderId = i32; -pub fn get_scheduled_tokens(total_emission_pool: Decimal) -> rust_decimal::Decimal { +pub fn get_scheduled_tokens(total_emission_pool: Decimal) -> Decimal { crate::reward_shares::get_scheduled_tokens_for_service_providers(total_emission_pool) } - -pub fn default_rewards_info( - total_emissions: u64, - epoch_duration: Duration, -) -> ResolvedSubDaoEpochRewardInfo { - let now = Utc::now(); - ResolvedSubDaoEpochRewardInfo { - epoch: 1, - epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), - epoch_period: (now - epoch_duration)..now, - epoch_emissions: Decimal::from(total_emissions), - rewards_issued_at: now, - } -} diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index 4cc9f8f0b..8eaa01ad8 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -271,12 +271,32 @@ impl DecimalRoundingExt for Decimal { #[cfg(test)] mod tests { use chrono::{Duration, Utc}; + use helium_crypto::PublicKeyBinary; use helium_proto::services::poc_mobile::{MobileRewardShare, PromotionReward}; + use std::str::FromStr; use crate::service_provider; use super::*; + pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; + pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + + pub fn default_rewards_info( + total_emissions: u64, + epoch_duration: Duration, + ) -> ResolvedSubDaoEpochRewardInfo { + let now = Utc::now(); + ResolvedSubDaoEpochRewardInfo { + epoch: 1, + epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_period: (now - epoch_duration)..now, + epoch_emissions: Decimal::from(total_emissions), + rewards_issued_at: now, + } + } + #[test] fn no_promotions() { let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); @@ -653,7 +673,6 @@ mod tests { assert_eq!(unallocated, 2); } - use crate::service_provider::default_rewards_info; use proptest::prelude::*; prop_compose! { From 97b8b9a1b20b9fde91dfbf1b32487cf852c2fa0d Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 19 Nov 2024 14:33:33 +0000 Subject: [PATCH 03/36] mor tidy --- mobile_config/src/sub_dao_epoch_reward_info.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index e9b6e3460..299fc49d8 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -20,16 +20,16 @@ pub struct ResolvedSubDaoEpochRewardInfo { #[derive(Clone, Debug, FromRow)] pub struct RawSubDaoEpochRewardInfo { #[sqlx(try_from = "i64")] - pub epoch: u64, - pub epoch_address: PublicKeyBinary, - pub sub_dao_address: PublicKeyBinary, + epoch: u64, + epoch_address: PublicKeyBinary, + sub_dao_address: PublicKeyBinary, #[sqlx(try_from = "i64")] - pub sub_dao_utility_score: u64, + sub_dao_utility_score: u64, #[sqlx(try_from = "i64")] - pub total_utility_score: u64, + total_utility_score: u64, #[sqlx(try_from = "i64")] - pub total_emissions: u64, - pub rewards_issued_at: DateTime, + total_emissions: u64, + rewards_issued_at: DateTime, } // server goes from raw to proto, client goes from proto to resolved From 76c0821fc9f89c7255e85b322451b091b103980b Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Wed, 20 Nov 2024 09:46:30 +0000 Subject: [PATCH 04/36] use latest proto msgs, avoid calculating subdao rewards locally --- Cargo.lock | 53 ++++++++++++------- Cargo.toml | 4 +- mobile_config/src/client/sub_dao_client.rs | 2 +- .../src/sub_dao_epoch_reward_info.rs | 50 ++++++++--------- mobile_config/src/sub_dao_service.rs | 4 +- mobile_verifier/src/reward_shares.rs | 4 +- .../src/service_provider/reward.rs | 4 +- .../tests/integrations/common/mod.rs | 4 +- 8 files changed, 67 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbbeef562..319f191b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,11 +1615,11 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#6c6d612ab6e77e03dacf338eb40319163dc7ae6a" dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "prost", "rand 0.8.5", "rand_chacha 0.3.0", @@ -1788,7 +1788,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -2630,7 +2630,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "notify", "serde", @@ -3212,7 +3212,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-literal", "http 0.2.11", "lazy_static", @@ -3794,7 +3794,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", "hex", "hex-literal", "itertools", @@ -3821,6 +3821,23 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" +dependencies = [ + "bytes", + "prost", + "prost-build", + "serde", + "serde_json", + "strum", + "strum_macros", + "tonic", + "tonic-build", +] + +[[package]] +name = "helium-proto" +version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" dependencies = [ "bytes", "prost", @@ -3874,7 +3891,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4290,7 +4307,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "humantime-serde", "metrics", @@ -4360,7 +4377,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -4402,7 +4419,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -4444,7 +4461,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http-serde", "humantime-serde", "iot-config", @@ -5033,7 +5050,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -5076,7 +5093,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "mobile-config", "prost", "rand 0.8.5", @@ -5112,7 +5129,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -5156,7 +5173,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-assignments", "hextree", "http-serde", @@ -5840,7 +5857,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5923,7 +5940,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6562,7 +6579,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "lazy_static", "metrics", diff --git a/Cargo.toml b/Cargo.toml index fae3f6697..acac87a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # - [patch.'https://github.com/helium/proto'] - helium-proto = { path = "../../proto" } +# [patch.'https://github.com/helium/proto'] +# helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index 628e015cc..7b5f9a6d3 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -49,7 +49,7 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { epoch: u64, ) -> Result, Self::Error> { let mut request = SubDaoEpochRewardInfoReqV1 { - sub_dao: sub_dao.clone().into(), + sub_dao_pubkey: sub_dao.clone().into(), epoch, signer: self.signing_key.public_key().into(), signature: vec![], diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 299fc49d8..834bb7016 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -10,8 +10,8 @@ use std::ops::Range; #[derive(Clone, Debug)] pub struct ResolvedSubDaoEpochRewardInfo { pub epoch: u64, - pub epoch_address: PublicKeyBinary, - pub sub_dao_address: PublicKeyBinary, + pub epoch_pubkey: PublicKeyBinary, + pub sub_dao_pubkey: PublicKeyBinary, pub epoch_period: Range>, pub epoch_emissions: Decimal, pub rewards_issued_at: DateTime, @@ -21,14 +21,12 @@ pub struct ResolvedSubDaoEpochRewardInfo { pub struct RawSubDaoEpochRewardInfo { #[sqlx(try_from = "i64")] epoch: u64, - epoch_address: PublicKeyBinary, - sub_dao_address: PublicKeyBinary, + epoch_pubkey: PublicKeyBinary, + sub_dao_pubkey: PublicKeyBinary, #[sqlx(try_from = "i64")] - sub_dao_utility_score: u64, + rewards_issued: u64, #[sqlx(try_from = "i64")] - total_utility_score: u64, - #[sqlx(try_from = "i64")] - total_emissions: u64, + delegation_rewards_issued: u64, rewards_issued_at: DateTime, } @@ -39,11 +37,10 @@ impl TryFrom for SubDaoEpochRewardInfoProto { fn try_from(info: RawSubDaoEpochRewardInfo) -> Result { Ok(Self { epoch: info.epoch, - address: info.epoch_address.into(), - sub_dao: info.sub_dao_address.into(), - sub_dao_utility_score: info.sub_dao_utility_score, - total_utility_score: info.total_utility_score, - total_emissions: info.total_emissions, + epoch_pubkey: info.epoch_pubkey.into(), + sub_dao_pubkey: info.sub_dao_pubkey.into(), + rewards_issued: info.rewards_issued, + delegation_rewards_issued: info.delegation_rewards_issued, rewards_issued_at: info.rewards_issued_at.encode_timestamp(), }) } @@ -55,15 +52,12 @@ impl TryFrom for ResolvedSubDaoEpochRewardInfo { fn try_from(info: SubDaoEpochRewardInfoProto) -> Result { let epoch_period: EpochPeriod = info.epoch.try_into()?; - // todo: confirm rounding requirements here - let epoch_rewards = Decimal::from( - info.total_emissions * (info.sub_dao_utility_score / info.total_utility_score), - ); + let epoch_rewards = Decimal::from(info.rewards_issued + info.delegation_rewards_issued); Ok(Self { epoch: info.epoch, - epoch_address: info.address.into(), - sub_dao_address: info.sub_dao.into(), + epoch_pubkey: info.epoch_pubkey.into(), + sub_dao_pubkey: info.sub_dao_pubkey.into(), epoch_period: epoch_period.period, epoch_emissions: epoch_rewards, rewards_issued_at: info.rewards_issued_at.to_timestamp()?, @@ -79,16 +73,14 @@ pub(crate) mod db { const GET_EPOCH_REWARD_INFO_SQL: &str = r#" SELECT - t_subdao.address AS epoch_address, - t_subdao.sub_dao AS sub_dao_address, - t_subdao.epoch, - t_subdao.utility_score, - t_dao.total_utility_score, - t_dao.total_rewards, - t_subdao.rewards_issued_at - FROM sub_dao_epoch_infos t_subdao - JOIN dao_epoch_infos t_dao ON t_subdao.epoch = t_dao.epoch - WHERE t_subdao.epoch = $1 AND t_subdao.sub_dao = $2 + address AS epoch_pubkey, + sub_dao AS sub_dao_pubkey, + epoch, + rewards_issued, + delegation_rewards_issued, + rewards_issued_at + FROM sub_dao_epoch_infos + WHERE epoch = $1 AND sub_dao = $2 "#; pub async fn get_info( diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs index 5c46cd97e..9e63fbb04 100644 --- a/mobile_config/src/sub_dao_service.rs +++ b/mobile_config/src/sub_dao_service.rs @@ -61,14 +61,14 @@ impl mobile_config::sub_dao_server::SubDao for SuDaoService { ) -> GrpcResult { let request = request.into_inner(); telemetry::count_request("sub_dao_reward_info", "info"); - custom_tracing::record_b58("sub_dao", &request.sub_dao); + custom_tracing::record_b58("sub_dao", &request.sub_dao_pubkey); custom_tracing::record("epoch", request.epoch); custom_tracing::record_b58("signer", &request.signer); self.verify_request_signature_for_info(&request)?; let epoch = request.epoch; - let sub_dao: PublicKeyBinary = request.sub_dao.into(); + let sub_dao: PublicKeyBinary = request.sub_dao_pubkey.into(); tracing::debug!(sub_dao = %sub_dao, epoch = epoch, "fetching sub_dao epoch reward info"); sub_dao_epoch_reward_info::db::get_info(&self.metadata_pool, epoch, sub_dao) diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 36ca36e91..ffa48a5e5 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -861,8 +861,8 @@ mod test { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index 8eaa01ad8..24ef346c3 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -289,8 +289,8 @@ mod tests { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 6f689e6ba..664152b82 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -399,8 +399,8 @@ pub fn default_rewards_info( let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_address: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_address: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), + sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, From a5493d617bf99a19fbeaafb2244a4487f7f19bff Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Thu, 21 Nov 2024 12:12:42 +0000 Subject: [PATCH 05/36] tweaks required by latest proto changes --- Cargo.lock | 8 ++++---- file_store/src/traits/msg_verify.rs | 5 +++-- mobile_config/src/client/settings.rs | 6 +++--- mobile_config/src/client/sub_dao_client.rs | 4 ++-- mobile_config/src/sub_dao_epoch_reward_info.rs | 2 +- mobile_config/src/sub_dao_service.rs | 4 ++-- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 319f191b1..2ee0240a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#6c6d612ab6e77e03dacf338eb40319163dc7ae6a" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#7c512285aa229d4101ec8793f86ff24d8406e7fc" dependencies = [ "base64 0.21.7", "byteorder", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#7c512285aa229d4101ec8793f86ff24d8406e7fc" dependencies = [ "bytes", "prost", @@ -3837,7 +3837,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" +source = "git+https://github.com/helium/proto?branch=master#99908bcedc340d1569f2001565b6f0fee4444fd8" dependencies = [ "bytes", "prost", @@ -6081,7 +6081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.5.0", + "heck 0.4.0", "itertools", "log", "multimap", diff --git a/file_store/src/traits/msg_verify.rs b/file_store/src/traits/msg_verify.rs index a8401cb36..6cb287279 100644 --- a/file_store/src/traits/msg_verify.rs +++ b/file_store/src/traits/msg_verify.rs @@ -4,6 +4,7 @@ use helium_proto::services::{ iot_config, mobile_config, poc_lora::{LoraBeaconReportReqV1, LoraStreamSessionInitV1, LoraWitnessReportReqV1}, poc_mobile::{self, ServiceProviderBoostedRewardsBannedRadioReqV1}, + sub_dao, }; use helium_proto::{ services::poc_mobile::{ @@ -98,8 +99,8 @@ impl_msg_verify!(mobile_config::GatewayInfoStreamResV2, signature); impl_msg_verify!(mobile_config::BoostedHexInfoStreamReqV1, signature); impl_msg_verify!(mobile_config::BoostedHexModifiedInfoStreamReqV1, signature); impl_msg_verify!(mobile_config::BoostedHexInfoStreamResV1, signature); -impl_msg_verify!(mobile_config::SubDaoEpochRewardInfoReqV1, signature); -impl_msg_verify!(mobile_config::SubDaoEpochRewardInfoResV1, signature); +impl_msg_verify!(sub_dao::SubDaoEpochRewardInfoReqV1, signature); +impl_msg_verify!(sub_dao::SubDaoEpochRewardInfoResV1, signature); impl_msg_verify!(poc_mobile::SubscriberVerifiedMappingEventReqV1, signature); impl_msg_verify!(poc_mobile::HexUsageStatsReqV1, signature); impl_msg_verify!(poc_mobile::RadioUsageStatsReqV1, signature); diff --git a/mobile_config/src/client/settings.rs b/mobile_config/src/client/settings.rs index 79a2132ce..7818c4de5 100644 --- a/mobile_config/src/client/settings.rs +++ b/mobile_config/src/client/settings.rs @@ -1,4 +1,4 @@ -use helium_proto::services::{mobile_config, Channel, Endpoint}; +use helium_proto::services::{mobile_config, sub_dao, Channel, Endpoint}; use humantime_serde::re::humantime; use serde::Deserialize; use std::{str::FromStr, sync::Arc, time::Duration}; @@ -49,9 +49,9 @@ fn default_cache_ttl_in_secs() -> Duration { } impl Settings { - pub fn connect_epoch_client(&self) -> mobile_config::sub_dao_client::SubDaoClient { + pub fn connect_epoch_client(&self) -> sub_dao::sub_dao_client::SubDaoClient { let channel = connect_channel(self); - mobile_config::sub_dao_client::SubDaoClient::new(channel) + sub_dao::sub_dao_client::SubDaoClient::new(channel) } pub fn connect_gateway_client(&self) -> mobile_config::GatewayClient { diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index 7b5f9a6d3..dc2bfb6ed 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -4,7 +4,7 @@ use file_store::traits::MsgVerify; use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; use helium_proto::{ services::{ - mobile_config::{self, SubDaoEpochRewardInfoReqV1}, + sub_dao::{self, SubDaoEpochRewardInfoReqV1}, Channel, }, Message, @@ -13,7 +13,7 @@ use std::{error::Error, sync::Arc, time::Duration}; #[derive(Clone)] pub struct SubDaoClient { - pub client: mobile_config::sub_dao_client::SubDaoClient, + pub client: sub_dao::sub_dao_client::SubDaoClient, signing_key: Arc, config_pubkey: PublicKey, } diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 834bb7016..6956cf8b4 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -2,7 +2,7 @@ use crate::EpochPeriod; use chrono::{DateTime, Utc}; use file_store::traits::{TimestampDecode, TimestampEncode}; use helium_crypto::PublicKeyBinary; -use helium_proto::services::mobile_config::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; +use helium_proto::services::sub_dao::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; use rust_decimal::prelude::*; use sqlx::FromRow; use std::ops::Range; diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs index 9e63fbb04..59b6de627 100644 --- a/mobile_config/src/sub_dao_service.rs +++ b/mobile_config/src/sub_dao_service.rs @@ -5,7 +5,7 @@ use chrono::Utc; use file_store::traits::{MsgVerify, TimestampEncode}; use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; use helium_proto::{ - services::mobile_config::{self, SubDaoEpochRewardInfoReqV1, SubDaoEpochRewardInfoResV1}, + services::sub_dao::{self, SubDaoEpochRewardInfoReqV1, SubDaoEpochRewardInfoResV1}, Message, }; use sqlx::{Pool, Postgres}; @@ -54,7 +54,7 @@ impl SuDaoService { } #[tonic::async_trait] -impl mobile_config::sub_dao_server::SubDao for SuDaoService { +impl sub_dao::sub_dao_server::SubDao for SuDaoService { async fn info( &self, request: Request, From 0150abff7f383ea6f707be9a93ab07254de5adbc Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Thu, 21 Nov 2024 14:26:47 +0000 Subject: [PATCH 06/36] misc tweaks and additions --- Cargo.lock | 4 +- iot_verifier/src/reward_share.rs | 1 + iot_verifier/src/rewarder.rs | 2 + .../src/sub_dao_epoch_reward_info.rs | 2 - mobile_verifier/src/lib.rs | 18 +++++++++ mobile_verifier/src/reward_shares.rs | 37 ++++++++++++++++--- mobile_verifier/src/rewarder.rs | 6 +-- 7 files changed, 56 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ee0240a0..8cb6f9543 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#7c512285aa229d4101ec8793f86ff24d8406e7fc" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#b88898c850794ae70bc6c65ea8bc41aa6ad5526b" dependencies = [ "base64 0.21.7", "byteorder", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#7c512285aa229d4101ec8793f86ff24d8406e7fc" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#b88898c850794ae70bc6c65ea8bc41aa6ad5526b" dependencies = [ "bytes", "prost", diff --git a/iot_verifier/src/reward_share.rs b/iot_verifier/src/reward_share.rs index eeb7dfb4a..f35cdb55a 100644 --- a/iot_verifier/src/reward_share.rs +++ b/iot_verifier/src/reward_share.rs @@ -286,6 +286,7 @@ impl GatewayShares { start_period: reward_period.start.encode_timestamp(), end_period: reward_period.end.encode_timestamp(), reward: Some(ProtoReward::GatewayReward(gateway_reward)), + epoch: 0, // placeholder, todo: remove }, ) }) diff --git a/iot_verifier/src/rewarder.rs b/iot_verifier/src/rewarder.rs index 570653e2f..3c875c0c9 100644 --- a/iot_verifier/src/rewarder.rs +++ b/iot_verifier/src/rewarder.rs @@ -303,6 +303,7 @@ pub async fn reward_operational( start_period: reward_period.start.encode_timestamp(), end_period: reward_period.end.encode_timestamp(), reward: Some(ProtoReward::OperationalReward(op_fund_reward)), + epoch: 0, // placeholder, todo: remove }, [], ) @@ -366,6 +367,7 @@ async fn write_unallocated_reward( reward_type: unallocated_type as i32, amount: unallocated_amount, })), + epoch: 0, // placeholder, todo: remove }; rewards_sink.write(unallocated_reward, []).await?.await??; }; diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 6956cf8b4..212761400 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -30,7 +30,6 @@ pub struct RawSubDaoEpochRewardInfo { rewards_issued_at: DateTime, } -// server goes from raw to proto, client goes from proto to resolved impl TryFrom for SubDaoEpochRewardInfoProto { type Error = anyhow::Error; @@ -46,7 +45,6 @@ impl TryFrom for SubDaoEpochRewardInfoProto { } } -// server returns the proto struct to client, client resolves to the resolved struct impl TryFrom for ResolvedSubDaoEpochRewardInfo { type Error = anyhow::Error; diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index 17ad5d268..d7186fb64 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -22,6 +22,9 @@ pub mod unique_connections; pub use settings::Settings; use async_trait::async_trait; +use rust_decimal::prelude::ToPrimitive; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; use std::error::Error; pub const MOBILE_SUB_DAO_ONCHAIN_ADDRESS: &str = "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk"; @@ -99,3 +102,18 @@ impl IsAuthorized for mobile_config::client::AuthorizationClient { self.verify_authorized_key(address, role).await } } + +pub struct PriceConverter; + +impl PriceConverter { + pub fn hnt_bones_to_pricer_format(hnt_bone_price: Decimal) -> u64 { + (hnt_bone_price * dec!(1_0000_0000) * dec!(1_0000_0000)) + .to_u64() + .unwrap_or_default() + } + + // Hnt prices are supplied from pricer in 10^8 + pub fn pricer_format_to_hnt_bones(hnt_price: u64) -> Decimal { + Decimal::from(hnt_price) / dec!(1_0000_0000) / dec!(1_0000_0000) + } +} diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index ffa48a5e5..e92b15740 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -9,6 +9,7 @@ use crate::{ subscriber_location::SubscriberValidatedLocations, subscriber_verified_mapping_event::VerifiedSubscriberVerifiedMappingEventShares, unique_connections::{self, UniqueConnectionCounts}, + PriceConverter, }; use chrono::{DateTime, Duration, Utc}; use coverage_point_calculator::{ @@ -151,6 +152,8 @@ impl TransferRewards { } = self; let start_period = reward_info.epoch_period.start.encode_timestamp(); let end_period = reward_info.epoch_period.end.encode_timestamp(); + let price = PriceConverter::hnt_bones_to_pricer_format(self.hnt_bone_price); + rewards .into_iter() .map(move |(hotspot_key, reward)| { @@ -169,11 +172,7 @@ impl TransferRewards { hotspot_key: hotspot_key.into(), dc_transfer_reward, rewardable_bytes: reward.bytes_rewarded, - price: (self.hnt_bone_price - * dec!(1_0000_0000) - * dec!(1_0000_0000)) - .to_u64() - .unwrap_or_default(), + price, }, )), }, @@ -869,6 +868,34 @@ mod test { } } + #[test] + fn test_poc_scheduled_tokens() { + let rewards_info = default_rewards_info(100_000_000_000_000, Duration::hours(1)); + let v = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions); + assert_eq!(dec!(60_000_000_000_000), v); + } + + #[test] + fn test_mappers_scheduled_tokens() { + let rewards_info = default_rewards_info(100_000_000_000_000, Duration::hours(1)); + let v = get_scheduled_tokens_for_mappers(rewards_info.epoch_emissions); + assert_eq!(dec!(20_000_000_000_000), v); + } + + #[test] + fn test_service_provider_scheduled_tokens() { + let rewards_info = default_rewards_info(100_000_000_000_000, Duration::hours(1)); + let v = get_scheduled_tokens_for_service_providers(rewards_info.epoch_emissions); + assert_eq!(dec!(10_000_000_000_000), v); + } + + #[test] + fn test_oracles_scheduled_tokens() { + let rewards_info = default_rewards_info(100_000_000_000_000, Duration::hours(1)); + let v = get_scheduled_tokens_for_oracles(rewards_info.epoch_emissions); + assert_eq!(dec!(4_000_000_000_000), v); + } + #[tokio::test] async fn subscriber_rewards() { const NUM_SUBSCRIBERS: u64 = 10_000; diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 665d9a9dd..e0601e433 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -46,7 +46,6 @@ use mobile_config::{ use price::PriceTracker; use reward_scheduler::Scheduler; use rust_decimal::{prelude::*, Decimal}; -use rust_decimal_macros::dec; use sqlx::{PgExecutor, Pool, Postgres}; use std::{ops::Range, time::Duration}; use task_manager::{ManagedTask, TaskManager}; @@ -260,10 +259,7 @@ where .price(&helium_proto::BlockchainTokenTypeV1::Hnt) .await?; - // Hnt prices are supplied in 10^8, so we must convert them to Decimal - let hnt_bone_price = Decimal::from(hnt_price) - / dec!(1_0000_0000) // Per Hnt token - / dec!(1_0000_0000); // Per Bone + let hnt_bone_price = PriceConverter::pricer_format_to_hnt_bones(hnt_price); // process rewards for poc and data transfer let poc_dc_shares = reward_poc_and_dc( From 53073d0afd2af2d11e0ad73fc1f38b442dbf2670 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Thu, 21 Nov 2024 14:59:15 +0000 Subject: [PATCH 07/36] output price in manifest --- Cargo.lock | 6 +++--- iot_verifier/src/rewarder.rs | 1 + mobile_verifier/src/rewarder.rs | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cb6f9543..adb24190d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#b88898c850794ae70bc6c65ea8bc41aa6ad5526b" +source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#5d49bc4b1e7bbfa5e3954b4a5683651019bd2c63" dependencies = [ "base64 0.21.7", "byteorder", @@ -1625,7 +1625,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", ] @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#b88898c850794ae70bc6c65ea8bc41aa6ad5526b" +source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#5d49bc4b1e7bbfa5e3954b4a5683651019bd2c63" dependencies = [ "bytes", "prost", diff --git a/iot_verifier/src/rewarder.rs b/iot_verifier/src/rewarder.rs index 3c875c0c9..e72f0bbd3 100644 --- a/iot_verifier/src/rewarder.rs +++ b/iot_verifier/src/rewarder.rs @@ -175,6 +175,7 @@ impl Rewarder { written_files, reward_data: Some(IotRewardData(reward_data)), epoch: 0, // TODO: replace placeholder value + price: 0, // TODO: replace placeholder value }, [], ) diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index e0601e433..0ae740133 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -339,6 +339,7 @@ where written_files, reward_data: Some(MobileRewardData(reward_data)), epoch: reward_info.epoch, + price: hnt_price, }, [], ) From 55e97a8727f9f89992b1d70d0dfab8a54e2f9401 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 22 Nov 2024 12:24:50 +0000 Subject: [PATCH 08/36] use latest proto msg definitions --- Cargo.lock | 8 +++---- mobile_config/src/client/sub_dao_client.rs | 8 +++---- .../src/sub_dao_epoch_reward_info.rs | 22 +++++++++---------- mobile_config/src/sub_dao_service.rs | 10 ++++----- mobile_verifier/src/cli/reward_from_db.rs | 7 +++--- mobile_verifier/src/reward_shares.rs | 4 ++-- mobile_verifier/src/rewarder.rs | 8 +++---- .../src/service_provider/reward.rs | 6 ++--- .../tests/integrations/common/mod.rs | 6 ++--- 9 files changed, 36 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index adb24190d..a83575a18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#5d49bc4b1e7bbfa5e3954b4a5683651019bd2c63" +source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#81ccaccf5826a2781e11e055faf8125e893c521d" dependencies = [ "base64 0.21.7", "byteorder", @@ -1625,7 +1625,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", ] @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#5d49bc4b1e7bbfa5e3954b4a5683651019bd2c63" +source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#81ccaccf5826a2781e11e055faf8125e893c521d" dependencies = [ "bytes", "prost", @@ -6081,7 +6081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.4.0", + "heck 0.5.0", "itertools", "log", "multimap", diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index dc2bfb6ed..dc23d0f52 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -1,7 +1,7 @@ use super::{call_with_retry, ClientError, Settings}; use crate::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; use file_store::traits::MsgVerify; -use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; +use helium_crypto::{Keypair, PublicKey, Sign}; use helium_proto::{ services::{ sub_dao::{self, SubDaoEpochRewardInfoReqV1}, @@ -34,7 +34,7 @@ pub trait SubDaoEpochRewardInfoResolver: Clone + Send + Sync + 'static { async fn resolve_info( &self, - sub_dao: &PublicKeyBinary, + sub_dao: &str, epoch: u64, ) -> Result, Self::Error>; } @@ -45,11 +45,11 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { async fn resolve_info( &self, - sub_dao: &PublicKeyBinary, + sub_dao: &str, epoch: u64, ) -> Result, Self::Error> { let mut request = SubDaoEpochRewardInfoReqV1 { - sub_dao_pubkey: sub_dao.clone().into(), + sub_dao_address: sub_dao.into(), epoch, signer: self.signing_key.public_key().into(), signature: vec![], diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 212761400..dd814d4d2 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -1,7 +1,6 @@ use crate::EpochPeriod; use chrono::{DateTime, Utc}; use file_store::traits::{TimestampDecode, TimestampEncode}; -use helium_crypto::PublicKeyBinary; use helium_proto::services::sub_dao::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; use rust_decimal::prelude::*; use sqlx::FromRow; @@ -10,8 +9,8 @@ use std::ops::Range; #[derive(Clone, Debug)] pub struct ResolvedSubDaoEpochRewardInfo { pub epoch: u64, - pub epoch_pubkey: PublicKeyBinary, - pub sub_dao_pubkey: PublicKeyBinary, + pub epoch_address: String, + pub sub_dao_address: String, pub epoch_period: Range>, pub epoch_emissions: Decimal, pub rewards_issued_at: DateTime, @@ -21,8 +20,8 @@ pub struct ResolvedSubDaoEpochRewardInfo { pub struct RawSubDaoEpochRewardInfo { #[sqlx(try_from = "i64")] epoch: u64, - epoch_pubkey: PublicKeyBinary, - sub_dao_pubkey: PublicKeyBinary, + epoch_address: String, + sub_dao_address: String, #[sqlx(try_from = "i64")] rewards_issued: u64, #[sqlx(try_from = "i64")] @@ -36,8 +35,8 @@ impl TryFrom for SubDaoEpochRewardInfoProto { fn try_from(info: RawSubDaoEpochRewardInfo) -> Result { Ok(Self { epoch: info.epoch, - epoch_pubkey: info.epoch_pubkey.into(), - sub_dao_pubkey: info.sub_dao_pubkey.into(), + epoch_address: info.epoch_address, + sub_dao_address: info.sub_dao_address, rewards_issued: info.rewards_issued, delegation_rewards_issued: info.delegation_rewards_issued, rewards_issued_at: info.rewards_issued_at.encode_timestamp(), @@ -54,8 +53,8 @@ impl TryFrom for ResolvedSubDaoEpochRewardInfo { Ok(Self { epoch: info.epoch, - epoch_pubkey: info.epoch_pubkey.into(), - sub_dao_pubkey: info.sub_dao_pubkey.into(), + epoch_address: info.epoch_address, + sub_dao_address: info.sub_dao_address, epoch_period: epoch_period.period, epoch_emissions: epoch_rewards, rewards_issued_at: info.rewards_issued_at.to_timestamp()?, @@ -66,7 +65,6 @@ impl TryFrom for ResolvedSubDaoEpochRewardInfo { pub(crate) mod db { use crate::sub_dao_epoch_reward_info::RawSubDaoEpochRewardInfo; - use helium_crypto::PublicKeyBinary; use sqlx::PgExecutor; const GET_EPOCH_REWARD_INFO_SQL: &str = r#" @@ -84,14 +82,14 @@ pub(crate) mod db { pub async fn get_info( db: impl PgExecutor<'_>, epoch: u64, - sub_dao: PublicKeyBinary, + sub_dao_address: &str, ) -> anyhow::Result> { let mut query: sqlx::QueryBuilder = sqlx::QueryBuilder::new(GET_EPOCH_REWARD_INFO_SQL); Ok(query .build_query_as::() .bind(epoch as i64) - .bind(sub_dao.to_string()) + .bind(sub_dao_address) .fetch_optional(db) .await?) } diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs index 59b6de627..8cf73ef20 100644 --- a/mobile_config/src/sub_dao_service.rs +++ b/mobile_config/src/sub_dao_service.rs @@ -3,7 +3,7 @@ use crate::{ }; use chrono::Utc; use file_store::traits::{MsgVerify, TimestampEncode}; -use helium_crypto::{Keypair, PublicKey, PublicKeyBinary, Sign}; +use helium_crypto::{Keypair, PublicKey, Sign}; use helium_proto::{ services::sub_dao::{self, SubDaoEpochRewardInfoReqV1, SubDaoEpochRewardInfoResV1}, Message, @@ -61,17 +61,17 @@ impl sub_dao::sub_dao_server::SubDao for SuDaoService { ) -> GrpcResult { let request = request.into_inner(); telemetry::count_request("sub_dao_reward_info", "info"); - custom_tracing::record_b58("sub_dao", &request.sub_dao_pubkey); + custom_tracing::record("sub_dao", &request.sub_dao_address); custom_tracing::record("epoch", request.epoch); custom_tracing::record_b58("signer", &request.signer); self.verify_request_signature_for_info(&request)?; let epoch = request.epoch; - let sub_dao: PublicKeyBinary = request.sub_dao_pubkey.into(); - tracing::debug!(sub_dao = %sub_dao, epoch = epoch, "fetching sub_dao epoch reward info"); + let sub_dao_address = request.sub_dao_address; + tracing::debug!(sub_dao_address = %sub_dao_address, epoch = epoch, "fetching sub_dao epoch reward info"); - sub_dao_epoch_reward_info::db::get_info(&self.metadata_pool, epoch, sub_dao) + sub_dao_epoch_reward_info::db::get_info(&self.metadata_pool, epoch, &sub_dao_address) .await .map_err(|_| Status::internal("error fetching sub_dao epoch reward info"))? .map_or_else( diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index c623319af..9f306849b 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -9,14 +9,14 @@ use crate::{ unique_connections, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, }; use anyhow::Result; -use helium_crypto::{PublicKey, PublicKeyBinary}; +use helium_crypto::PublicKey; use helium_proto::services::poc_mobile as proto; use mobile_config::{ boosted_hex_info::BoostedHexes, client::{sub_dao_client::SubDaoEpochRewardInfoResolver, SubDaoClient}, }; use serde_json::json; -use std::{collections::HashMap, str::FromStr}; +use std::collections::HashMap; /// Reward an epoch from the entries in the database #[derive(Debug, clap::Args)] @@ -31,10 +31,9 @@ impl Cmd { let reward_epoch = self.reward_epoch; - let sub_dao_pubkey = PublicKeyBinary::from_str(MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; let sub_dao_rewards_client = SubDaoClient::from_settings(&settings.config_client)?; let reward_info = sub_dao_rewards_client - .resolve_info(&sub_dao_pubkey, reward_epoch) + .resolve_info(MOBILE_SUB_DAO_ONCHAIN_ADDRESS, reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index e92b15740..0c7f0e3b2 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -860,8 +860,8 @@ mod test { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_address: EPOCH_ADDRESS.into(), + sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 0ae740133..082f7dd06 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -24,7 +24,6 @@ use file_store::{ use futures_util::TryFutureExt; use self::boosted_hex_eligibility::BoostedHexEligibility; -use helium_crypto::PublicKeyBinary; use helium_proto::{ reward_manifest::RewardData::MobileRewardData, services::poc_mobile::{ @@ -57,7 +56,7 @@ mod db; const REWARDS_NOT_CURRENT_DELAY_PERIOD: i64 = 5; pub struct Rewarder { - sub_dao_pubkey: PublicKeyBinary, + sub_dao_address: String, pool: Pool, carrier_client: A, hex_service_client: B, @@ -139,9 +138,8 @@ where price_tracker: PriceTracker, speedtest_averages: FileSinkClient, ) -> anyhow::Result { - let sub_dao_pubkey = PublicKeyBinary::from_str(MOBILE_SUB_DAO_ONCHAIN_ADDRESS)?; Ok(Self { - sub_dao_pubkey, + sub_dao_address: MOBILE_SUB_DAO_ONCHAIN_ADDRESS.into(), pool, carrier_client, hex_service_client, @@ -160,7 +158,7 @@ where let next_reward_epoch = next_reward_epoch(&self.pool).await?; let reward_info = self .sub_dao_epoch_reward_client - .resolve_info(&self.sub_dao_pubkey, next_reward_epoch) + .resolve_info(&self.sub_dao_address, next_reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index 24ef346c3..dba8e5c91 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -271,9 +271,7 @@ impl DecimalRoundingExt for Decimal { #[cfg(test)] mod tests { use chrono::{Duration, Utc}; - use helium_crypto::PublicKeyBinary; use helium_proto::services::poc_mobile::{MobileRewardShare, PromotionReward}; - use std::str::FromStr; use crate::service_provider; @@ -289,8 +287,8 @@ mod tests { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_address: EPOCH_ADDRESS.into(), + sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 664152b82..677a3dbff 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -77,7 +77,7 @@ impl SubDaoEpochRewardInfoResolver for MockSubDaoRewardsClient { async fn resolve_info( &self, - _sub_dao: &PublicKeyBinary, + _sub_dao: &str, _epoch: u64, ) -> Result, Self::Error> { Ok(self.info.clone()) @@ -399,8 +399,8 @@ pub fn default_rewards_info( let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { epoch: 1, - epoch_pubkey: PublicKeyBinary::from_str(EPOCH_ADDRESS).unwrap(), - sub_dao_pubkey: PublicKeyBinary::from_str(SUB_DAO_ADDRESS).unwrap(), + epoch_address: EPOCH_ADDRESS.into(), + sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, epoch_emissions: Decimal::from(total_emissions), rewards_issued_at: now, From 42f4e19664bc8e637824a8c9aca46cfc973eabf9 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 22 Nov 2024 15:44:47 +0000 Subject: [PATCH 09/36] actually start the subdao service. fix db access --- mobile_config/src/main.rs | 20 ++++++++-- .../src/sub_dao_epoch_reward_info.rs | 37 +++++++++++++------ mobile_config/src/sub_dao_service.rs | 6 +-- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/mobile_config/src/main.rs b/mobile_config/src/main.rs index b869bef2c..61db4f316 100644 --- a/mobile_config/src/main.rs +++ b/mobile_config/src/main.rs @@ -2,15 +2,18 @@ use anyhow::{Error, Result}; use clap::Parser; use futures::future::LocalBoxFuture; use futures_util::TryFutureExt; -use helium_proto::services::mobile_config::{ - AdminServer, AuthorizationServer, CarrierServiceServer, EntityServer, GatewayServer, - HexBoostingServer, +use helium_proto::services::{ + mobile_config::{ + AdminServer, AuthorizationServer, CarrierServiceServer, EntityServer, GatewayServer, + HexBoostingServer, + }, + sub_dao::SubDaoServer, }; use mobile_config::{ admin_service::AdminService, authorization_service::AuthorizationService, carrier_service::CarrierService, entity_service::EntityService, gateway_service::GatewayService, hex_boosting_service::HexBoostingService, key_cache::KeyCache, - mobile_radio_tracker::MobileRadioTracker, settings::Settings, + mobile_radio_tracker::MobileRadioTracker, settings::Settings, sub_dao_service::SubDaoService, }; use std::{net::SocketAddr, path::PathBuf, time::Duration}; use task_manager::{ManagedTask, TaskManager}; @@ -96,6 +99,12 @@ impl Daemon { settings.signing_keypair()?, ); + let sub_dao_svc = SubDaoService::new( + key_cache.clone(), + metadata_pool.clone(), + settings.signing_keypair()?, + ); + let listen_addr = settings.listen; let grpc_server = GrpcServer { listen_addr, @@ -105,6 +114,7 @@ impl Daemon { entity_svc, carrier_svc, hex_boosting_svc, + sub_dao_svc, }; TaskManager::builder() @@ -128,6 +138,7 @@ pub struct GrpcServer { entity_svc: EntityService, carrier_svc: CarrierService, hex_boosting_svc: HexBoostingService, + sub_dao_svc: SubDaoService, } impl ManagedTask for GrpcServer { @@ -146,6 +157,7 @@ impl ManagedTask for GrpcServer { .add_service(EntityServer::new(self.entity_svc)) .add_service(CarrierServiceServer::new(self.carrier_svc)) .add_service(HexBoostingServer::new(self.hex_boosting_svc)) + .add_service(SubDaoServer::new(self.sub_dao_svc)) .serve_with_shutdown(self.listen_addr, shutdown) .map_err(Error::from) .await diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index dd814d4d2..09288fbe8 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -3,7 +3,6 @@ use chrono::{DateTime, Utc}; use file_store::traits::{TimestampDecode, TimestampEncode}; use helium_proto::services::sub_dao::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; use rust_decimal::prelude::*; -use sqlx::FromRow; use std::ops::Range; #[derive(Clone, Debug)] @@ -16,15 +15,12 @@ pub struct ResolvedSubDaoEpochRewardInfo { pub rewards_issued_at: DateTime, } -#[derive(Clone, Debug, FromRow)] +#[derive(Clone, Debug)] pub struct RawSubDaoEpochRewardInfo { - #[sqlx(try_from = "i64")] epoch: u64, epoch_address: String, sub_dao_address: String, - #[sqlx(try_from = "i64")] rewards_issued: u64, - #[sqlx(try_from = "i64")] delegation_rewards_issued: u64, rewards_issued_at: DateTime, } @@ -63,18 +59,19 @@ impl TryFrom for ResolvedSubDaoEpochRewardInfo { } pub(crate) mod db { - use crate::sub_dao_epoch_reward_info::RawSubDaoEpochRewardInfo; - use sqlx::PgExecutor; + use chrono::{DateTime, Utc}; + use file_store::traits::TimestampDecode; + use sqlx::{postgres::PgRow, FromRow, PgExecutor, Row}; const GET_EPOCH_REWARD_INFO_SQL: &str = r#" SELECT address AS epoch_pubkey, sub_dao AS sub_dao_pubkey, - epoch, - rewards_issued, - delegation_rewards_issued, - rewards_issued_at + epoch::BIGINT, + delegation_rewards_issued::BIGINT AS rewards_issued, + delegation_rewards_issued::BIGINT, + rewards_issued_at::BIGINT FROM sub_dao_epoch_infos WHERE epoch = $1 AND sub_dao = $2 "#; @@ -93,4 +90,22 @@ pub(crate) mod db { .fetch_optional(db) .await?) } + + impl FromRow<'_, PgRow> for RawSubDaoEpochRewardInfo { + fn from_row(row: &PgRow) -> sqlx::Result { + let rewards_issued_at: DateTime = (row.try_get::("rewards_issued_at")? + as u64) + .to_timestamp() + .map_err(|err| sqlx::Error::Decode(Box::new(err)))?; + + Ok(Self { + epoch: row.get::("epoch") as u64, + epoch_address: row.get::("epoch_address"), + sub_dao_address: row.get::("sub_dao_address"), + rewards_issued: row.get::("rewards_issued") as u64, + delegation_rewards_issued: row.get::("delegation_rewards_issued") as u64, + rewards_issued_at, + }) + } + } } diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs index 8cf73ef20..25e4ede92 100644 --- a/mobile_config/src/sub_dao_service.rs +++ b/mobile_config/src/sub_dao_service.rs @@ -12,13 +12,13 @@ use sqlx::{Pool, Postgres}; use std::sync::Arc; use tonic::{Request, Response, Status}; -pub struct SuDaoService { +pub struct SubDaoService { key_cache: KeyCache, metadata_pool: Pool, signing_key: Arc, } -impl SuDaoService { +impl SubDaoService { pub fn new(key_cache: KeyCache, metadata_pool: Pool, signing_key: Keypair) -> Self { Self { key_cache, @@ -54,7 +54,7 @@ impl SuDaoService { } #[tonic::async_trait] -impl sub_dao::sub_dao_server::SubDao for SuDaoService { +impl sub_dao::sub_dao_server::SubDao for SubDaoService { async fn info( &self, request: Request, From af2ac06ffd16177dc5d2245ef0c753c34a038fb3 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 25 Nov 2024 12:34:26 +0000 Subject: [PATCH 10/36] logging and layout tweaks --- mobile_verifier/src/rewarder.rs | 44 +++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 082f7dd06..f41db5296 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -41,6 +41,7 @@ use mobile_config::{ sub_dao_client::SubDaoEpochRewardInfoResolver, ClientError, }, sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo, + EpochPeriod, }; use price::PriceTracker; use reward_scheduler::Scheduler; @@ -154,27 +155,23 @@ where } pub async fn run(self, shutdown: triggered::Listener) -> anyhow::Result<()> { + tracing::info!("Starting rewarder"); + loop { let next_reward_epoch = next_reward_epoch(&self.pool).await?; - let reward_info = self - .sub_dao_epoch_reward_client - .resolve_info(&self.sub_dao_address, next_reward_epoch) - .await? - .ok_or(anyhow::anyhow!( - "No reward info found for epoch {}", - next_reward_epoch - ))?; + let next_reward_epoch_period = EpochPeriod::try_from(next_reward_epoch)?; let scheduler = Scheduler::new( self.reward_period_duration, - reward_info.epoch_period.start, - reward_info.epoch_period.end, + next_reward_epoch_period.period.start, + next_reward_epoch_period.period.end, self.reward_offset, ); + let now = Utc::now(); let sleep_duration = if scheduler.should_trigger(now) { if self.is_data_current(&scheduler.schedule_period).await? { - self.reward(reward_info).await?; + self.reward(next_reward_epoch).await?; continue; } else { chrono::Duration::minutes(REWARDS_NOT_CURRENT_DELAY_PERIOD).to_std()? @@ -195,6 +192,7 @@ where } } + tracing::info!("Stopping rewarder"); Ok(()) } @@ -244,13 +242,15 @@ where Ok(true) } - pub async fn reward(&self, reward_info: ResolvedSubDaoEpochRewardInfo) -> anyhow::Result<()> { - tracing::info!( - "Rewarding for epoch {} period: {} to {}", - reward_info.epoch, - reward_info.epoch_period.start, - reward_info.epoch_period.end - ); + pub async fn reward(&self, next_reward_epoch: u64) -> anyhow::Result<()> { + let reward_info = self + .sub_dao_epoch_reward_client + .resolve_info(&self.sub_dao_address, next_reward_epoch) + .await? + .ok_or(anyhow::anyhow!( + "No reward info found for epoch {}", + next_reward_epoch + ))?; let hnt_price = self .price_tracker @@ -259,6 +259,14 @@ where let hnt_bone_price = PriceConverter::pricer_format_to_hnt_bones(hnt_price); + tracing::info!( + "Rewarding for epoch {} period: {} to {} with hnt bone price: {}", + reward_info.epoch, + reward_info.epoch_period.start, + reward_info.epoch_period.end, + hnt_bone_price + ); + // process rewards for poc and data transfer let poc_dc_shares = reward_poc_and_dc( &self.pool, From eb6b93a3cc023fcd5144fd1545b6c0e462c4354b Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Thu, 28 Nov 2024 12:03:00 +0000 Subject: [PATCH 11/36] misc tweaks and test addition --- .../src/sub_dao_epoch_reward_info.rs | 10 ++++++---- mobile_verifier/src/lib.rs | 4 ++++ mobile_verifier/src/reward_shares.rs | 20 +++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 09288fbe8..1aa14a0f4 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -66,8 +66,8 @@ pub(crate) mod db { const GET_EPOCH_REWARD_INFO_SQL: &str = r#" SELECT - address AS epoch_pubkey, - sub_dao AS sub_dao_pubkey, + address AS epoch_address, + sub_dao AS sub_dao_address, epoch::BIGINT, delegation_rewards_issued::BIGINT AS rewards_issued, delegation_rewards_issued::BIGINT, @@ -83,12 +83,14 @@ pub(crate) mod db { ) -> anyhow::Result> { let mut query: sqlx::QueryBuilder = sqlx::QueryBuilder::new(GET_EPOCH_REWARD_INFO_SQL); - Ok(query + let res = query .build_query_as::() .bind(epoch as i64) .bind(sub_dao_address) .fetch_optional(db) - .await?) + .await?; + tracing::info!("get_info: {:?}", res); + Ok(res) } impl FromRow<'_, PgRow> for RawSubDaoEpochRewardInfo { diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index d7186fb64..089a668ec 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -116,4 +116,8 @@ impl PriceConverter { pub fn pricer_format_to_hnt_bones(hnt_price: u64) -> Decimal { Decimal::from(hnt_price) / dec!(1_0000_0000) / dec!(1_0000_0000) } + + pub fn pricer_format_to_hnt(hnt_price: u64) -> Decimal { + Decimal::from(hnt_price) / dec!(1_0000_0000) + } } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 0c7f0e3b2..2c44c5690 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -2617,4 +2617,24 @@ mod test { .unwrap_or(0); assert_eq!(unallocated_sp_reward_amount, 0); } + + #[test] + fn test_price_conversion() { + let hnt_dollar_price = dec!(1.0); + let hnt_dollar_bone_price = dec!(0.00000001); + let hnt_price_from_pricer = 100000000_u64; + + assert_eq!( + hnt_dollar_bone_price, + PriceConverter::pricer_format_to_hnt_bones(hnt_price_from_pricer) + ); + assert_eq!( + hnt_price_from_pricer, + PriceConverter::hnt_bones_to_pricer_format(hnt_dollar_bone_price) + ); + assert_eq!( + hnt_dollar_price, + PriceConverter::pricer_format_to_hnt(hnt_price_from_pricer) + ); + } } From 0a23888f161079c65f2fb037df2cba7f9b579ff8 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 29 Nov 2024 10:08:12 +0000 Subject: [PATCH 12/36] remove epoch from mobile reward share --- Cargo.lock | 6 +++--- file_store/src/cli/mod.rs | 2 ++ file_store/src/error.rs | 2 ++ mobile_verifier/src/reward_shares.rs | 3 --- mobile_verifier/src/rewarder.rs | 1 - mobile_verifier/src/service_provider/reward.rs | 2 -- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a83575a18..ecaaa7d16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#81ccaccf5826a2781e11e055faf8125e893c521d" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" dependencies = [ "base64 0.21.7", "byteorder", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/sub-dao-epoch-support#81ccaccf5826a2781e11e055faf8125e893c521d" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" dependencies = [ "bytes", "prost", @@ -3837,7 +3837,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#99908bcedc340d1569f2001565b6f0fee4444fd8" +source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" dependencies = [ "bytes", "prost", diff --git a/file_store/src/cli/mod.rs b/file_store/src/cli/mod.rs index 5eaccb9f3..81b66a30e 100644 --- a/file_store/src/cli/mod.rs +++ b/file_store/src/cli/mod.rs @@ -1,6 +1,8 @@ pub mod bucket; pub mod dump; pub mod dump_mobile_rewards; +pub mod import_iot_rewards; +pub mod import_mobile_rewards; pub mod info; use crate::Result; diff --git a/file_store/src/error.rs b/file_store/src/error.rs index 3083357cf..6d1523f63 100644 --- a/file_store/src/error.rs +++ b/file_store/src/error.rs @@ -41,6 +41,8 @@ pub enum Error { //Not recommended for internal use! #[error("external error")] ExternalError(#[from] Box), + #[error("general error")] + Anyhow(#[from] anyhow::Error), } #[derive(Error, Debug)] diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 2c44c5690..690c61ecb 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -166,7 +166,6 @@ impl TransferRewards { proto::MobileRewardShare { start_period, end_period, - epoch: reward_info.epoch, reward: Some(proto::mobile_reward_share::Reward::GatewayReward( proto::GatewayReward { hotspot_key: hotspot_key.into(), @@ -288,7 +287,6 @@ impl MapperShares { proto::MobileRewardShare { start_period: reward_info.epoch_period.start.encode_timestamp(), end_period: reward_info.epoch_period.end.encode_timestamp(), - epoch: reward_info.epoch, reward: Some(ProtoReward::SubscriberReward(subscriber_reward)), }, ) @@ -374,7 +372,6 @@ pub fn coverage_point_to_mobile_reward_share( let base = proto::MobileRewardShare { start_period: reward_info.epoch_period.start.encode_timestamp(), end_period: reward_info.epoch_period.end.encode_timestamp(), - epoch: reward_info.epoch, reward: None, }; diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index f41db5296..2b00b16bc 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -679,7 +679,6 @@ async fn write_unallocated_reward( let unallocated_reward = proto::MobileRewardShare { start_period: reward_info.epoch_period.start.encode_timestamp(), end_period: reward_info.epoch_period.end.encode_timestamp(), - epoch: reward_info.epoch, reward: Some(ProtoReward::UnallocatedReward(UnallocatedReward { reward_type: unallocated_type as i32, amount: unallocated_amount, diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index dba8e5c91..d0ead60b0 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -155,7 +155,6 @@ impl RewardInfo { proto::MobileRewardShare { start_period: reward_info.epoch_period.start.encode_timestamp(), end_period: reward_info.epoch_period.end.encode_timestamp(), - epoch: reward_info.epoch, reward: Some(proto::Reward::ServiceProviderReward( proto::ServiceProviderReward { service_provider_id: self.sp_id, @@ -201,7 +200,6 @@ impl RewardInfo { proto::MobileRewardShare { start_period: reward_info.epoch_period.start.encode_timestamp(), end_period: reward_info.epoch_period.end.encode_timestamp(), - epoch: reward_info.epoch, reward: Some(proto::Reward::PromotionReward(proto::PromotionReward { service_provider_amount, matched_amount, From cd6e7184c1b88430616464f58dd28d30e8ee32c8 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 2 Dec 2024 11:20:50 +0000 Subject: [PATCH 13/36] refactor price handling --- Cargo.lock | 1 + mobile_verifier/Cargo.toml | 1 + mobile_verifier/src/lib.rs | 35 +++++++------- mobile_verifier/src/reward_shares.rs | 46 ++++++++++--------- mobile_verifier/src/rewarder.rs | 26 +++++++---- .../tests/integrations/hex_boosting.rs | 31 +++++++++---- .../tests/integrations/rewarder_poc_dc.rs | 6 ++- 7 files changed, 87 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecaaa7d16..523333f06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5173,6 +5173,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", + "helium-lib", "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-assignments", "hextree", diff --git a/mobile_verifier/Cargo.toml b/mobile_verifier/Cargo.toml index 84e6c61b3..b3aedd3e7 100644 --- a/mobile_verifier/Cargo.toml +++ b/mobile_verifier/Cargo.toml @@ -14,6 +14,7 @@ thiserror = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } h3o = { workspace = true, features = ["geo"] } +helium-lib = { workspace = true } hextree = { workspace = true } http-serde = { workspace = true } clap = { workspace = true } diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index 089a668ec..7b602fb72 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -22,9 +22,7 @@ pub mod unique_connections; pub use settings::Settings; use async_trait::async_trait; -use rust_decimal::prelude::ToPrimitive; use rust_decimal::Decimal; -use rust_decimal_macros::dec; use std::error::Error; pub const MOBILE_SUB_DAO_ONCHAIN_ADDRESS: &str = "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk"; @@ -103,21 +101,24 @@ impl IsAuthorized for mobile_config::client::AuthorizationClient { } } -pub struct PriceConverter; - -impl PriceConverter { - pub fn hnt_bones_to_pricer_format(hnt_bone_price: Decimal) -> u64 { - (hnt_bone_price * dec!(1_0000_0000) * dec!(1_0000_0000)) - .to_u64() - .unwrap_or_default() - } - - // Hnt prices are supplied from pricer in 10^8 - pub fn pricer_format_to_hnt_bones(hnt_price: u64) -> Decimal { - Decimal::from(hnt_price) / dec!(1_0000_0000) / dec!(1_0000_0000) - } +#[derive(Clone, Debug)] +pub struct HntPrice { + pub hnt_price_in_bones: u64, + pub hnt_price: Decimal, + pub price_per_hnt_bone: Decimal, + pub decimals: u8, +} - pub fn pricer_format_to_hnt(hnt_price: u64) -> Decimal { - Decimal::from(hnt_price) / dec!(1_0000_0000) +impl HntPrice { + pub fn new(hnt_price_in_bones: u64, decimals: u8) -> Self { + let hnt_price = + Decimal::from(hnt_price_in_bones) / Decimal::from(10_u64.pow(decimals as u32)); + let price_per_hnt_bone = hnt_price / Decimal::from(10_u64.pow(decimals as u32)); + Self { + hnt_price_in_bones, + hnt_price, + price_per_hnt_bone, + decimals, + } } } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 690c61ecb..e667f8cac 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -9,7 +9,7 @@ use crate::{ subscriber_location::SubscriberValidatedLocations, subscriber_verified_mapping_event::VerifiedSubscriberVerifiedMappingEventShares, unique_connections::{self, UniqueConnectionCounts}, - PriceConverter, + HntPrice, }; use chrono::{DateTime, Duration, Utc}; use coverage_point_calculator::{ @@ -66,7 +66,7 @@ pub struct TransferRewards { reward_scale: Decimal, rewards: HashMap, reward_sum: Decimal, - hnt_bone_price: Decimal, + hnt_price: HntPrice, } #[derive(Copy, Clone, Debug)] @@ -102,7 +102,7 @@ impl TransferRewards { } pub async fn from_transfer_sessions( - hnt_bone_price: Decimal, + hnt_price: HntPrice, transfer_sessions: HotspotMap, reward_shares: &DataTransferAndPocAllocatedRewardBuckets, ) -> Self { @@ -111,8 +111,10 @@ impl TransferRewards { .into_iter() // Calculate rewards per hotspot .map(|(pub_key, rewardable)| { - let bones = - dc_to_hnt_bones(Decimal::from(rewardable.rewardable_dc), hnt_bone_price); + let bones = dc_to_hnt_bones( + Decimal::from(rewardable.rewardable_dc), + hnt_price.price_per_hnt_bone, + ); reward_sum += bones; ( pub_key, @@ -137,7 +139,7 @@ impl TransferRewards { reward_scale, rewards, reward_sum: reward_sum * reward_scale, - hnt_bone_price, + hnt_price, } } @@ -152,7 +154,7 @@ impl TransferRewards { } = self; let start_period = reward_info.epoch_period.start.encode_timestamp(); let end_period = reward_info.epoch_period.end.encode_timestamp(); - let price = PriceConverter::hnt_bones_to_pricer_format(self.hnt_bone_price); + let price = self.hnt_price.hnt_price_in_bones; rewards .into_iter() @@ -1005,8 +1007,11 @@ mod test { let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + let data_transfer_rewards = - TransferRewards::from_transfer_sessions(dec!(1.0), data_transfer_map, &reward_shares) + TransferRewards::from_transfer_sessions(hnt_price, data_transfer_map, &reward_shares) .await; assert_eq!(data_transfer_rewards.reward(&owner), dec!(0.00002)); @@ -1053,11 +1058,14 @@ mod test { // set our rewards info let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); let data_transfer_rewards = TransferRewards::from_transfer_sessions( - dec!(1.0), + hnt_price, aggregated_data_transfer_sessions, &reward_shares, ) @@ -2618,20 +2626,14 @@ mod test { #[test] fn test_price_conversion() { let hnt_dollar_price = dec!(1.0); - let hnt_dollar_bone_price = dec!(0.00000001); let hnt_price_from_pricer = 100000000_u64; + let hnt_dollar_bone_price = dec!(0.00000001); - assert_eq!( - hnt_dollar_bone_price, - PriceConverter::pricer_format_to_hnt_bones(hnt_price_from_pricer) - ); - assert_eq!( - hnt_price_from_pricer, - PriceConverter::hnt_bones_to_pricer_format(hnt_dollar_bone_price) - ); - assert_eq!( - hnt_dollar_price, - PriceConverter::pricer_format_to_hnt(hnt_price_from_pricer) - ); + let pricer_decimals = 8; + let hnt_price = HntPrice::new(hnt_price_from_pricer, pricer_decimals); + + assert_eq!(hnt_dollar_bone_price, hnt_price.price_per_hnt_bone); + assert_eq!(hnt_price_from_pricer, hnt_price.hnt_price_in_bones); + assert_eq!(hnt_dollar_price, hnt_price.hnt_price); } } diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 2b00b16bc..32ab2efd3 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -10,8 +10,13 @@ use crate::{ service_provider::{self, ServiceProviderDCSessions, ServiceProviderPromotions}, sp_boosted_rewards_bans, speedtests, speedtests_average::SpeedtestAverages, +<<<<<<< HEAD subscriber_location, subscriber_verified_mapping_event, telemetry, unique_connections, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, +======= + subscriber_location, subscriber_verified_mapping_event, telemetry, HntPrice, Settings, + MOBILE_SUB_DAO_ONCHAIN_ADDRESS, +>>>>>>> 63ed4905 (refactor price handling) }; use anyhow::bail; use chrono::{DateTime, TimeZone, Utc}; @@ -24,6 +29,7 @@ use file_store::{ use futures_util::TryFutureExt; use self::boosted_hex_eligibility::BoostedHexEligibility; +use helium_lib::token::Token; use helium_proto::{ reward_manifest::RewardData::MobileRewardData, services::poc_mobile::{ @@ -252,19 +258,19 @@ where next_reward_epoch ))?; - let hnt_price = self + let pricer_hnt_price = self .price_tracker .price(&helium_proto::BlockchainTokenTypeV1::Hnt) .await?; - let hnt_bone_price = PriceConverter::pricer_format_to_hnt_bones(hnt_price); + let hnt_price = HntPrice::new(pricer_hnt_price, Token::Hnt.decimals()); tracing::info!( "Rewarding for epoch {} period: {} to {} with hnt bone price: {}", reward_info.epoch, reward_info.epoch_period.start, reward_info.epoch_period.end, - hnt_bone_price + hnt_price.price_per_hnt_bone ); // process rewards for poc and data transfer @@ -274,7 +280,7 @@ where &self.mobile_rewards, &self.speedtest_averages, &reward_info, - hnt_bone_price, + hnt_price.clone(), ) .await?; @@ -296,7 +302,7 @@ where sp_promotions.clone(), &self.mobile_rewards, &reward_info, - hnt_bone_price, + hnt_price.price_per_hnt_bone, ) .await?; @@ -345,7 +351,7 @@ where written_files, reward_data: Some(MobileRewardData(reward_data)), epoch: reward_info.epoch, - price: hnt_price, + price: hnt_price.hnt_price_in_bones, }, [], ) @@ -383,13 +389,13 @@ pub async fn reward_poc_and_dc( mobile_rewards: &FileSinkClient, speedtest_avg_sink: &FileSinkClient, reward_info: &ResolvedSubDaoEpochRewardInfo, - hnt_bone_price: Decimal, + hnt_price: HntPrice, ) -> anyhow::Result { let mut reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(reward_info.epoch_emissions); let transfer_rewards = TransferRewards::from_transfer_sessions( - hnt_bone_price, + hnt_price, data_session::aggregate_hotspot_data_sessions_to_dc(pool, &reward_info.epoch_period) .await?, &reward_shares, @@ -634,7 +640,7 @@ pub async fn reward_service_providers( sp_promotions: ServiceProviderPromotions, mobile_rewards: &FileSinkClient, reward_info: &ResolvedSubDaoEpochRewardInfo, - mobile_bone_price: Decimal, + hnt_bone_price: Decimal, ) -> anyhow::Result<()> { use service_provider::ServiceProviderRewardInfos; @@ -644,7 +650,7 @@ pub async fn reward_service_providers( dc_sessions, sp_promotions, total_sp_rewards, - mobile_bone_price, + hnt_bone_price, reward_info.clone(), ); diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index 4af9f9d7b..9d04c45f3 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -21,7 +21,7 @@ use mobile_verifier::{ cell_type::CellType, coverage::CoverageObject, heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, - radio_threshold, reward_shares, rewarder, speedtests, + radio_threshold, reward_shares, rewarder, speedtests, HntPrice, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -140,6 +140,8 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { .to_u64() .unwrap(); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -148,7 +150,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -326,6 +328,8 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -334,7 +338,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards(&mut mobile_rewards) ); @@ -487,6 +491,9 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res .unwrap(); let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -495,7 +502,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -661,6 +668,8 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -669,7 +678,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards(&mut mobile_rewards) ); @@ -792,6 +801,8 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: .to_u64() .unwrap(); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -800,7 +811,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -971,6 +982,8 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( .to_u64() .unwrap(); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -979,7 +992,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -1175,6 +1188,8 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an .to_u64() .unwrap(); + let hnt_price = HntPrice::new(1000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -1183,7 +1198,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index e7d59f855..d6da747a6 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -17,7 +17,7 @@ use mobile_verifier::{ heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, reward_shares, rewarder, sp_boosted_rewards_bans::{self, BannedRadioReport}, - speedtests, unique_connections, + speedtests, unique_connections, HntPrice, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -61,6 +61,8 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + let hnt_price = HntPrice::new(10000000000000000, 8); + let (_, rewards) = tokio::join!( // run rewards for poc and dc rewarder::reward_poc_and_dc( @@ -69,7 +71,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - dec!(0.0001) + hnt_price ), receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 3, false) ); From 25c54e3245628b47add09402b848b03109d05d4f Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 2 Dec 2024 14:25:49 +0000 Subject: [PATCH 14/36] comment price asserts for clarity --- mobile_verifier/src/reward_shares.rs | 4 +++ .../tests/integrations/hex_boosting.rs | 35 +++++++++++++++---- .../tests/integrations/rewarder_poc_dc.rs | 3 ++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index e667f8cac..5ccb3192f 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -1009,6 +1009,8 @@ mod test { // todo: rebalance the tests to use a normalised hnt price let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let data_transfer_rewards = TransferRewards::from_transfer_sessions(hnt_price, data_transfer_map, &reward_shares) @@ -1060,6 +1062,8 @@ mod test { // todo: rebalance the tests to use a normalised hnt price let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index 9d04c45f3..133c5375d 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -140,7 +140,10 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { .to_u64() .unwrap(); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -328,7 +331,10 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -492,7 +498,10 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -668,7 +677,10 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -801,7 +813,10 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: .to_u64() .unwrap(); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -982,7 +997,10 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( .to_u64() .unwrap(); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1188,7 +1206,10 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an .to_u64() .unwrap(); - let hnt_price = HntPrice::new(1000000000000000, 8); + // todo: rebalance the tests to use a normalised hnt price + let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index d6da747a6..159be7a60 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -61,7 +61,10 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + // todo: rebalance the tests to use a normalised hnt price let hnt_price = HntPrice::new(10000000000000000, 8); + assert_eq!(hnt_price.hnt_price, dec!(100000000)); + assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc From 23691cfb1ca4db76a1df362fde3989b6c689ad88 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 3 Dec 2024 12:28:50 +0000 Subject: [PATCH 15/36] remove contagion from local test modules --- file_store/src/cli/mod.rs | 2 -- iot_packet_verifier/src/verifier.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/file_store/src/cli/mod.rs b/file_store/src/cli/mod.rs index 81b66a30e..5eaccb9f3 100644 --- a/file_store/src/cli/mod.rs +++ b/file_store/src/cli/mod.rs @@ -1,8 +1,6 @@ pub mod bucket; pub mod dump; pub mod dump_mobile_rewards; -pub mod import_iot_rewards; -pub mod import_mobile_rewards; pub mod info; use crate::Result; diff --git a/iot_packet_verifier/src/verifier.rs b/iot_packet_verifier/src/verifier.rs index 6c5b24dc8..5033705b4 100644 --- a/iot_packet_verifier/src/verifier.rs +++ b/iot_packet_verifier/src/verifier.rs @@ -352,7 +352,6 @@ impl PacketWriter for Vec { } } -#[cfg(test)] mod tests { use super::*; From 472e1cfb09c1c810de76508e9507212b886831c6 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 3 Dec 2024 12:44:59 +0000 Subject: [PATCH 16/36] bump deps --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 523333f06..817bd73da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" dependencies = [ "base64 0.21.7", "byteorder", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#bac002ac419dd8f75af81cd30afc67871ac2c93a" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" dependencies = [ "bytes", "prost", @@ -3837,7 +3837,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" +source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" dependencies = [ "bytes", "prost", From 82788b306f4de3fb36876263fc709a6aec1ebab5 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 3 Dec 2024 12:46:16 +0000 Subject: [PATCH 17/36] bump deps --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 817bd73da..a89634a5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#fffce9d335b1e5d74ffd5da27ddba6e60b6d9d7c" dependencies = [ "bytes", "prost", @@ -3837,7 +3837,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" +source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" dependencies = [ "bytes", "prost", From 3713e880cca5864159d5c3111543fc9e31f7d9b2 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Wed, 4 Dec 2024 12:45:18 +0000 Subject: [PATCH 18/36] Fix rebase artifacts --- iot_packet_verifier/src/verifier.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/iot_packet_verifier/src/verifier.rs b/iot_packet_verifier/src/verifier.rs index 5033705b4..6c5b24dc8 100644 --- a/iot_packet_verifier/src/verifier.rs +++ b/iot_packet_verifier/src/verifier.rs @@ -352,6 +352,7 @@ impl PacketWriter for Vec { } } +#[cfg(test)] mod tests { use super::*; From 35b86db4275806ae1cf7043edc3a13ab3f8d50df Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 6 Dec 2024 11:54:45 +0000 Subject: [PATCH 19/36] review tweaks --- file_store/src/error.rs | 2 -- mobile_config/src/client/mod.rs | 6 ++-- mobile_config/src/lib.rs | 19 ++++------ .../src/sub_dao_epoch_reward_info.rs | 22 +++++++----- mobile_config/src/sub_dao_service.rs | 4 +-- mobile_verifier/src/cli/reward_from_db.rs | 2 +- mobile_verifier/src/reward_shares.rs | 36 +++++++++---------- mobile_verifier/src/rewarder.rs | 12 +++---- .../src/service_provider/reward.rs | 2 +- mobile_verifier/src/telemetry.rs | 2 +- .../tests/integrations/common/mod.rs | 2 +- 11 files changed, 52 insertions(+), 57 deletions(-) diff --git a/file_store/src/error.rs b/file_store/src/error.rs index 6d1523f63..3083357cf 100644 --- a/file_store/src/error.rs +++ b/file_store/src/error.rs @@ -41,8 +41,6 @@ pub enum Error { //Not recommended for internal use! #[error("external error")] ExternalError(#[from] Box), - #[error("general error")] - Anyhow(#[from] anyhow::Error), } #[derive(Error, Debug)] diff --git a/mobile_config/src/client/mod.rs b/mobile_config/src/client/mod.rs index 1c3f3587d..7cc06d723 100644 --- a/mobile_config/src/client/mod.rs +++ b/mobile_config/src/client/mod.rs @@ -31,8 +31,10 @@ pub enum ClientError { UnknownServiceProvider(String), #[error("Invalid GatewayInfo proto response {0}")] InvalidGatewayInfoProto(#[from] crate::gateway_info::GatewayInfoProtoParseError), - #[error("error {0}")] - AnyhowError(#[from] anyhow::Error), + #[error("Invalid SubDaoRewardInfo proto response {0}")] + InvalidSubDaoRewardInfoProto( + #[from] crate::sub_dao_epoch_reward_info::SubDaoRewardInfoParseError, + ), } macro_rules! call_with_retry { diff --git a/mobile_config/src/lib.rs b/mobile_config/src/lib.rs index c41c0342b..3e6d26729 100644 --- a/mobile_config/src/lib.rs +++ b/mobile_config/src/lib.rs @@ -1,5 +1,4 @@ -use anyhow::anyhow; -use chrono::{DateTime, Duration, TimeZone, Utc}; +use chrono::{DateTime, Duration, Utc}; use helium_crypto::PublicKey; use helium_proto::services::mobile_config::AdminKeyRole as ProtoKeyRole; use serde::Serialize; @@ -104,18 +103,12 @@ pub struct EpochPeriod { pub period: Range>, } -impl TryFrom for EpochPeriod { - type Error = anyhow::Error; - - fn try_from(next_reward_epoch: u64) -> anyhow::Result { - let start_time = Utc - .timestamp_opt(0, 0) - .single() - .ok_or_else(|| anyhow!("Failed to get Unix epoch start time"))? - + Duration::days(next_reward_epoch as i64); +impl From for EpochPeriod { + fn from(next_reward_epoch: u64) -> Self { + let start_time = DateTime::::UNIX_EPOCH + Duration::days(next_reward_epoch as i64); let end_time = start_time + Duration::days(1); - Ok(EpochPeriod { + EpochPeriod { period: start_time..end_time, - }) + } } } diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 1aa14a0f4..699ccc38b 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -7,7 +7,7 @@ use std::ops::Range; #[derive(Clone, Debug)] pub struct ResolvedSubDaoEpochRewardInfo { - pub epoch: u64, + pub epoch_day: u64, pub epoch_address: String, pub sub_dao_address: String, pub epoch_period: Range>, @@ -25,30 +25,34 @@ pub struct RawSubDaoEpochRewardInfo { rewards_issued_at: DateTime, } -impl TryFrom for SubDaoEpochRewardInfoProto { - type Error = anyhow::Error; +#[derive(thiserror::Error, Debug)] +pub enum SubDaoRewardInfoParseError { + #[error("file_store: {0}")] + FileStore(#[from] file_store::Error), +} - fn try_from(info: RawSubDaoEpochRewardInfo) -> Result { - Ok(Self { +impl From for SubDaoEpochRewardInfoProto { + fn from(info: RawSubDaoEpochRewardInfo) -> Self { + Self { epoch: info.epoch, epoch_address: info.epoch_address, sub_dao_address: info.sub_dao_address, rewards_issued: info.rewards_issued, delegation_rewards_issued: info.delegation_rewards_issued, rewards_issued_at: info.rewards_issued_at.encode_timestamp(), - }) + } } } impl TryFrom for ResolvedSubDaoEpochRewardInfo { - type Error = anyhow::Error; + type Error = SubDaoRewardInfoParseError; fn try_from(info: SubDaoEpochRewardInfoProto) -> Result { - let epoch_period: EpochPeriod = info.epoch.try_into()?; + let epoch_period: EpochPeriod = info.epoch.into(); let epoch_rewards = Decimal::from(info.rewards_issued + info.delegation_rewards_issued); Ok(Self { - epoch: info.epoch, + epoch_day: info.epoch, epoch_address: info.epoch_address, sub_dao_address: info.sub_dao_address, epoch_period: epoch_period.period, diff --git a/mobile_config/src/sub_dao_service.rs b/mobile_config/src/sub_dao_service.rs index 25e4ede92..129036115 100644 --- a/mobile_config/src/sub_dao_service.rs +++ b/mobile_config/src/sub_dao_service.rs @@ -80,9 +80,7 @@ impl sub_dao::sub_dao_server::SubDao for SubDaoService { Err(Status::not_found(epoch.to_string())) }, |info| { - let info = info.try_into().map_err(|_| { - Status::internal("error serializing sub_dao epoch reward info") - })?; + let info = info.into(); let mut res = SubDaoEpochRewardInfoResV1 { info: Some(info), timestamp: Utc::now().encode_timestamp(), diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index 9f306849b..a2891b5a9 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -75,7 +75,7 @@ impl Cmd { let radio_rewards = reward_shares .into_rewards( DataTransferAndPocAllocatedRewardBuckets::new(reward_info.epoch_emissions), - &reward_info, + &reward_info.epoch_period, ) .ok_or(anyhow::anyhow!("no rewardable events"))? .1; diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 5ccb3192f..199346976 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -226,7 +226,7 @@ impl MapperShares { pub fn into_subscriber_rewards( self, - reward_info: &'_ ResolvedSubDaoEpochRewardInfo, + reward_period: &'_ Range>, reward_per_share: Decimal, ) -> impl Iterator + '_ { let mut subscriber_rewards: HashMap, proto::SubscriberReward> = HashMap::new(); @@ -287,8 +287,8 @@ impl MapperShares { ( total_reward_amount, proto::MobileRewardShare { - start_period: reward_info.epoch_period.start.encode_timestamp(), - end_period: reward_info.epoch_period.end.encode_timestamp(), + start_period: reward_period.start.encode_timestamp(), + end_period: reward_period.end.encode_timestamp(), reward: Some(ProtoReward::SubscriberReward(subscriber_reward)), }, ) @@ -305,7 +305,7 @@ pub fn dc_to_hnt_bones(dc_amount: Decimal, hnt_bone_price: Decimal) -> Decimal { pub fn coverage_point_to_mobile_reward_share( coverage_points: coverage_point_calculator::CoveragePoints, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_period: &Range>, radio_id: &RadioId, poc_reward: u64, rewards_per_share: CalculatedPocRewardShares, @@ -372,8 +372,8 @@ pub fn coverage_point_to_mobile_reward_share( }); let base = proto::MobileRewardShare { - start_period: reward_info.epoch_period.start.encode_timestamp(), - end_period: reward_info.epoch_period.end.encode_timestamp(), + start_period: reward_period.start.encode_timestamp(), + end_period: reward_period.end.encode_timestamp(), reward: None, }; @@ -565,7 +565,7 @@ impl CoverageShares { pub fn into_rewards( self, reward_shares: DataTransferAndPocAllocatedRewardBuckets, - reward_info: &'_ ResolvedSubDaoEpochRewardInfo, + reward_period: &Range>, ) -> Option<( CalculatedPocRewardShares, impl Iterator + '_, @@ -603,7 +603,7 @@ impl CoverageShares { reward_shares, processed_radios.iter().map(|radio| &radio.points), ) else { - tracing::info!(?reward_info.epoch_period, "could not calculate reward shares"); + tracing::info!(?reward_period, "could not calculate reward shares"); return None; }; @@ -623,7 +623,7 @@ impl CoverageShares { let (mobile_reward_v1, mobile_reward_v2) = coverage_point_to_mobile_reward_share( points, - reward_info, + reward_period, &radio_id, poc_reward, rewards_per_share, @@ -858,7 +858,7 @@ mod test { ) -> ResolvedSubDaoEpochRewardInfo { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { - epoch: 1, + epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, @@ -935,7 +935,7 @@ mod test { // get the summed rewards allocated to subscribers for discovery location let mut allocated_mapper_rewards = 0_u64; for (reward_amount, subscriber_share) in - shares.into_subscriber_rewards(&rewards_info, rewards_per_share) + shares.into_subscriber_rewards(&rewards_info.epoch_period, rewards_per_share) { if let Some(MobileReward::SubscriberReward(r)) = subscriber_share.reward { assert_eq!( @@ -1291,7 +1291,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .unwrap() .1 .next() @@ -1696,7 +1696,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .unwrap() .1 { @@ -1879,7 +1879,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .unwrap() .1 { @@ -2015,7 +2015,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .unwrap() .1 { @@ -2152,7 +2152,7 @@ mod test { ) .await .unwrap() - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .unwrap() .1 { @@ -2424,7 +2424,7 @@ mod test { // gw2 does not have enough speedtests for a mulitplier let expected_hotspot = gw1; for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in coverage_shares - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .expect("rewards output") .1 { @@ -2449,7 +2449,7 @@ mod test { let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); assert!(coverage_shares - .into_rewards(reward_shares, &rewards_info) + .into_rewards(reward_shares, &rewards_info.epoch_period) .is_none()); } diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 32ab2efd3..c23a092c5 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -165,7 +165,7 @@ where loop { let next_reward_epoch = next_reward_epoch(&self.pool).await?; - let next_reward_epoch_period = EpochPeriod::try_from(next_reward_epoch)?; + let next_reward_epoch_period = EpochPeriod::from(next_reward_epoch); let scheduler = Scheduler::new( self.reward_period_duration, @@ -267,7 +267,7 @@ where tracing::info!( "Rewarding for epoch {} period: {} to {} with hnt bone price: {}", - reward_info.epoch, + reward_info.epoch_day, reward_info.epoch_period.start, reward_info.epoch_period.end, hnt_price.price_per_hnt_bone @@ -329,7 +329,7 @@ where unique_connections::db::clear(&mut transaction, &reward_info.epoch_period.start).await?; // subscriber_location::clear_location_shares(&mut transaction, &reward_period.end).await?; - save_next_reward_epoch(&mut transaction, reward_info.epoch + 1).await?; + save_next_reward_epoch(&mut transaction, reward_info.epoch_day + 1).await?; transaction.commit().await?; @@ -350,7 +350,7 @@ where end_timestamp: reward_info.epoch_period.end.encode_timestamp(), written_files, reward_data: Some(MobileRewardData(reward_data)), - epoch: reward_info.epoch, + epoch: reward_info.epoch_day, price: hnt_price.hnt_price_in_bones, }, [], @@ -498,7 +498,7 @@ async fn reward_poc( let (unallocated_poc_amount, calculated_poc_rewards_per_share) = if let Some((calculated_poc_rewards_per_share, mobile_reward_shares)) = - coverage_shares.into_rewards(reward_shares, reward_info) + coverage_shares.into_rewards(reward_shares, &reward_info.epoch_period) { // handle poc reward outputs let mut allocated_poc_rewards = 0_u64; @@ -585,7 +585,7 @@ pub async fn reward_mappers( let mut allocated_mapping_rewards = 0_u64; for (reward_amount, mapping_share) in - mapping_shares.into_subscriber_rewards(reward_info, rewards_per_share) + mapping_shares.into_subscriber_rewards(&reward_info.epoch_period, rewards_per_share) { allocated_mapping_rewards += reward_amount; mobile_rewards diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index d0ead60b0..f38015751 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -284,7 +284,7 @@ mod tests { ) -> ResolvedSubDaoEpochRewardInfo { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { - epoch: 1, + epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, diff --git a/mobile_verifier/src/telemetry.rs b/mobile_verifier/src/telemetry.rs index e213790d2..9c3e209d9 100644 --- a/mobile_verifier/src/telemetry.rs +++ b/mobile_verifier/src/telemetry.rs @@ -8,7 +8,7 @@ const DATA_TRANSFER_REWARDS_SCALE: &str = "data_transfer_rewards_scale"; pub async fn initialize(db: &Pool) -> anyhow::Result<()> { let next_reward_epoch = rewarder::next_reward_epoch(db).await?; - let epoch_period: EpochPeriod = next_reward_epoch.try_into()?; + let epoch_period: EpochPeriod = next_reward_epoch.into(); last_rewarded_end_time(epoch_period.period.start); Ok(()) } diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 677a3dbff..69df84b61 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -398,7 +398,7 @@ pub fn default_rewards_info( ) -> ResolvedSubDaoEpochRewardInfo { let now = Utc::now(); ResolvedSubDaoEpochRewardInfo { - epoch: 1, + epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), epoch_period: (now - epoch_duration)..now, From 7096d9e329be0265662405f31bfe1bc5aa2f4cae Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Thu, 12 Dec 2024 11:53:02 +0000 Subject: [PATCH 20/36] rename some things --- mobile_config/src/client/sub_dao_client.rs | 11 ++-- mobile_config/src/lib.rs | 6 +- .../src/sub_dao_epoch_reward_info.rs | 8 +-- mobile_verifier/src/lib.rs | 24 ++++---- mobile_verifier/src/reward_shares.rs | 49 +++++++--------- mobile_verifier/src/rewarder.rs | 43 ++++++-------- .../src/service_provider/reward.rs | 19 +++--- mobile_verifier/src/telemetry.rs | 4 +- .../tests/integrations/common/mod.rs | 13 ++--- .../tests/integrations/hex_boosting.rs | 58 +++++++++---------- .../tests/integrations/rewarder_poc_dc.rs | 10 ++-- 11 files changed, 113 insertions(+), 132 deletions(-) diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index dc23d0f52..3f89ea4c3 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -1,5 +1,5 @@ use super::{call_with_retry, ClientError, Settings}; -use crate::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; +use crate::sub_dao_epoch_reward_info::EpochRewardInfo; use file_store::traits::MsgVerify; use helium_crypto::{Keypair, PublicKey, Sign}; use helium_proto::{ @@ -36,7 +36,7 @@ pub trait SubDaoEpochRewardInfoResolver: Clone + Send + Sync + 'static { &self, sub_dao: &str, epoch: u64, - ) -> Result, Self::Error>; + ) -> Result, Self::Error>; } #[async_trait::async_trait] @@ -47,7 +47,7 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { &self, sub_dao: &str, epoch: u64, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let mut request = SubDaoEpochRewardInfoReqV1 { sub_dao_address: sub_dao.into(), epoch, @@ -64,10 +64,7 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { Ok(info_res) => { let response = info_res.into_inner(); response.verify(&self.config_pubkey)?; - response - .info - .map(ResolvedSubDaoEpochRewardInfo::try_from) - .transpose()? + response.info.map(EpochRewardInfo::try_from).transpose()? } Err(status) if status.code() == tonic::Code::NotFound => None, Err(status) => Err(status)?, diff --git a/mobile_config/src/lib.rs b/mobile_config/src/lib.rs index 3e6d26729..fc81cae09 100644 --- a/mobile_config/src/lib.rs +++ b/mobile_config/src/lib.rs @@ -99,15 +99,15 @@ impl std::fmt::Display for KeyRole { } } -pub struct EpochPeriod { +pub struct EpochInfo { pub period: Range>, } -impl From for EpochPeriod { +impl From for EpochInfo { fn from(next_reward_epoch: u64) -> Self { let start_time = DateTime::::UNIX_EPOCH + Duration::days(next_reward_epoch as i64); let end_time = start_time + Duration::days(1); - EpochPeriod { + EpochInfo { period: start_time..end_time, } } diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 699ccc38b..1481ed22b 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -1,4 +1,4 @@ -use crate::EpochPeriod; +use crate::EpochInfo; use chrono::{DateTime, Utc}; use file_store::traits::{TimestampDecode, TimestampEncode}; use helium_proto::services::sub_dao::SubDaoEpochRewardInfo as SubDaoEpochRewardInfoProto; @@ -6,7 +6,7 @@ use rust_decimal::prelude::*; use std::ops::Range; #[derive(Clone, Debug)] -pub struct ResolvedSubDaoEpochRewardInfo { +pub struct EpochRewardInfo { pub epoch_day: u64, pub epoch_address: String, pub sub_dao_address: String, @@ -44,11 +44,11 @@ impl From for SubDaoEpochRewardInfoProto { } } -impl TryFrom for ResolvedSubDaoEpochRewardInfo { +impl TryFrom for EpochRewardInfo { type Error = SubDaoRewardInfoParseError; fn try_from(info: SubDaoEpochRewardInfoProto) -> Result { - let epoch_period: EpochPeriod = info.epoch.into(); + let epoch_period: EpochInfo = info.epoch.into(); let epoch_rewards = Decimal::from(info.rewards_issued + info.delegation_rewards_issued); Ok(Self { diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index 7b602fb72..ce37c18b6 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -102,22 +102,22 @@ impl IsAuthorized for mobile_config::client::AuthorizationClient { } #[derive(Clone, Debug)] -pub struct HntPrice { - pub hnt_price_in_bones: u64, - pub hnt_price: Decimal, - pub price_per_hnt_bone: Decimal, +pub struct PriceInfo { + pub price_in_bones: u64, + pub price_per_token: Decimal, + pub price_per_bone: Decimal, pub decimals: u8, } -impl HntPrice { - pub fn new(hnt_price_in_bones: u64, decimals: u8) -> Self { - let hnt_price = - Decimal::from(hnt_price_in_bones) / Decimal::from(10_u64.pow(decimals as u32)); - let price_per_hnt_bone = hnt_price / Decimal::from(10_u64.pow(decimals as u32)); +impl PriceInfo { + pub fn new(price_in_bones: u64, decimals: u8) -> Self { + let price_per_token = + Decimal::from(price_in_bones) / Decimal::from(10_u64.pow(decimals as u32)); + let price_per_bone = price_per_token / Decimal::from(10_u64.pow(decimals as u32)); Self { - hnt_price_in_bones, - hnt_price, - price_per_hnt_bone, + price_in_bones, + price_per_token, + price_per_bone, decimals, } } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 199346976..6fb4b25db 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -9,7 +9,7 @@ use crate::{ subscriber_location::SubscriberValidatedLocations, subscriber_verified_mapping_event::VerifiedSubscriberVerifiedMappingEventShares, unique_connections::{self, UniqueConnectionCounts}, - HntPrice, + PriceInfo, }; use chrono::{DateTime, Duration, Utc}; use coverage_point_calculator::{ @@ -22,9 +22,7 @@ use helium_crypto::PublicKeyBinary; use helium_proto::services::{ poc_mobile as proto, poc_mobile::mobile_reward_share::Reward as ProtoReward, }; -use mobile_config::{ - boosted_hex_info::BoostedHexes, sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo, -}; +use mobile_config::{boosted_hex_info::BoostedHexes, sub_dao_epoch_reward_info::EpochRewardInfo}; use radio_reward_v2::{RadioRewardV2Ext, ToProtoDecimal}; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -66,7 +64,7 @@ pub struct TransferRewards { reward_scale: Decimal, rewards: HashMap, reward_sum: Decimal, - hnt_price: HntPrice, + price_info: PriceInfo, } #[derive(Copy, Clone, Debug)] @@ -102,7 +100,7 @@ impl TransferRewards { } pub async fn from_transfer_sessions( - hnt_price: HntPrice, + price_info: PriceInfo, transfer_sessions: HotspotMap, reward_shares: &DataTransferAndPocAllocatedRewardBuckets, ) -> Self { @@ -113,7 +111,7 @@ impl TransferRewards { .map(|(pub_key, rewardable)| { let bones = dc_to_hnt_bones( Decimal::from(rewardable.rewardable_dc), - hnt_price.price_per_hnt_bone, + price_info.price_per_bone, ); reward_sum += bones; ( @@ -139,13 +137,13 @@ impl TransferRewards { reward_scale, rewards, reward_sum: reward_sum * reward_scale, - hnt_price, + price_info, } } pub fn into_rewards( self, - reward_info: &'_ ResolvedSubDaoEpochRewardInfo, + reward_info: &'_ EpochRewardInfo, ) -> impl Iterator + '_ { let Self { reward_scale, @@ -154,7 +152,7 @@ impl TransferRewards { } = self; let start_period = reward_info.epoch_period.start.encode_timestamp(); let end_period = reward_info.epoch_period.end.encode_timestamp(); - let price = self.hnt_price.hnt_price_in_bones; + let price = self.price_info.price_in_bones; rewards .into_iter() @@ -852,12 +850,9 @@ mod test { (hnt_value / DC_USD_PRICE).round_dp_with_strategy(0, RoundingStrategy::ToNegativeInfinity) } - fn default_rewards_info( - total_emissions: u64, - epoch_duration: Duration, - ) -> ResolvedSubDaoEpochRewardInfo { + fn default_rewards_info(total_emissions: u64, epoch_duration: Duration) -> EpochRewardInfo { let now = Utc::now(); - ResolvedSubDaoEpochRewardInfo { + EpochRewardInfo { epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), @@ -1008,12 +1003,12 @@ mod test { DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let data_transfer_rewards = - TransferRewards::from_transfer_sessions(hnt_price, data_transfer_map, &reward_shares) + TransferRewards::from_transfer_sessions(price_info, data_transfer_map, &reward_shares) .await; assert_eq!(data_transfer_rewards.reward(&owner), dec!(0.00002)); @@ -1061,15 +1056,15 @@ mod test { let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); let data_transfer_rewards = TransferRewards::from_transfer_sessions( - hnt_price, + price_info, aggregated_data_transfer_sessions, &reward_shares, ) @@ -2634,10 +2629,10 @@ mod test { let hnt_dollar_bone_price = dec!(0.00000001); let pricer_decimals = 8; - let hnt_price = HntPrice::new(hnt_price_from_pricer, pricer_decimals); + let hnt_price = PriceInfo::new(hnt_price_from_pricer, pricer_decimals); - assert_eq!(hnt_dollar_bone_price, hnt_price.price_per_hnt_bone); - assert_eq!(hnt_price_from_pricer, hnt_price.hnt_price_in_bones); - assert_eq!(hnt_dollar_price, hnt_price.hnt_price); + assert_eq!(hnt_dollar_bone_price, hnt_price.price_per_bone); + assert_eq!(hnt_price_from_pricer, hnt_price.price_in_bones); + assert_eq!(hnt_dollar_price, hnt_price.price_per_token); } } diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index c23a092c5..30771803d 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -10,13 +10,8 @@ use crate::{ service_provider::{self, ServiceProviderDCSessions, ServiceProviderPromotions}, sp_boosted_rewards_bans, speedtests, speedtests_average::SpeedtestAverages, -<<<<<<< HEAD subscriber_location, subscriber_verified_mapping_event, telemetry, unique_connections, - Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, -======= - subscriber_location, subscriber_verified_mapping_event, telemetry, HntPrice, Settings, - MOBILE_SUB_DAO_ONCHAIN_ADDRESS, ->>>>>>> 63ed4905 (refactor price handling) + Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, PriceInfo }; use anyhow::bail; use chrono::{DateTime, TimeZone, Utc}; @@ -46,8 +41,8 @@ use mobile_config::{ hex_boosting_client::HexBoostingInfoResolver, sub_dao_client::SubDaoEpochRewardInfoResolver, ClientError, }, - sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo, - EpochPeriod, + sub_dao_epoch_reward_info::EpochRewardInfo, + EpochInfo, }; use price::PriceTracker; use reward_scheduler::Scheduler; @@ -165,7 +160,7 @@ where loop { let next_reward_epoch = next_reward_epoch(&self.pool).await?; - let next_reward_epoch_period = EpochPeriod::from(next_reward_epoch); + let next_reward_epoch_period = EpochInfo::from(next_reward_epoch); let scheduler = Scheduler::new( self.reward_period_duration, @@ -263,14 +258,14 @@ where .price(&helium_proto::BlockchainTokenTypeV1::Hnt) .await?; - let hnt_price = HntPrice::new(pricer_hnt_price, Token::Hnt.decimals()); + let price_info = PriceInfo::new(pricer_hnt_price, Token::Hnt.decimals()); tracing::info!( - "Rewarding for epoch {} period: {} to {} with hnt bone price: {}", + "Rewarding for epoch {} period: {} to {} with bone price: {}", reward_info.epoch_day, reward_info.epoch_period.start, reward_info.epoch_period.end, - hnt_price.price_per_hnt_bone + price_info.price_per_bone ); // process rewards for poc and data transfer @@ -280,7 +275,7 @@ where &self.mobile_rewards, &self.speedtest_averages, &reward_info, - hnt_price.clone(), + price_info.clone(), ) .await?; @@ -302,7 +297,7 @@ where sp_promotions.clone(), &self.mobile_rewards, &reward_info, - hnt_price.price_per_hnt_bone, + price_info.price_per_bone, ) .await?; @@ -351,7 +346,7 @@ where written_files, reward_data: Some(MobileRewardData(reward_data)), epoch: reward_info.epoch_day, - price: hnt_price.hnt_price_in_bones, + price: price_info.price_in_bones, }, [], ) @@ -388,14 +383,14 @@ pub async fn reward_poc_and_dc( hex_service_client: &impl HexBoostingInfoResolver, mobile_rewards: &FileSinkClient, speedtest_avg_sink: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, - hnt_price: HntPrice, + reward_info: &EpochRewardInfo, + price_info: PriceInfo, ) -> anyhow::Result { let mut reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(reward_info.epoch_emissions); let transfer_rewards = TransferRewards::from_transfer_sessions( - hnt_price, + price_info, data_session::aggregate_hotspot_data_sessions_to_dc(pool, &reward_info.epoch_period) .await?, &reward_shares, @@ -451,7 +446,7 @@ async fn reward_poc( hex_service_client: &impl HexBoostingInfoResolver, mobile_rewards: &FileSinkClient, speedtest_avg_sink: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, reward_shares: DataTransferAndPocAllocatedRewardBuckets, ) -> anyhow::Result<(Decimal, CalculatedPocRewardShares)> { let heartbeats = HeartbeatReward::validated(pool, &reward_info.epoch_period); @@ -531,7 +526,7 @@ async fn reward_poc( pub async fn reward_dc( mobile_rewards: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, transfer_rewards: TransferRewards, reward_shares: &DataTransferAndPocAllocatedRewardBuckets, ) -> anyhow::Result { @@ -556,7 +551,7 @@ pub async fn reward_dc( pub async fn reward_mappers( pool: &Pool, mobile_rewards: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, ) -> anyhow::Result<()> { // Mapper rewards currently include rewards for discovery mapping only. // Verification mapping rewards to be added @@ -614,7 +609,7 @@ pub async fn reward_mappers( pub async fn reward_oracles( mobile_rewards: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, ) -> anyhow::Result<()> { // atm 100% of oracle rewards are assigned to 'unallocated' let total_oracle_rewards = @@ -639,7 +634,7 @@ pub async fn reward_service_providers( dc_sessions: ServiceProviderDCSessions, sp_promotions: ServiceProviderPromotions, mobile_rewards: &FileSinkClient, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, hnt_bone_price: Decimal, ) -> anyhow::Result<()> { use service_provider::ServiceProviderRewardInfos; @@ -679,7 +674,7 @@ async fn write_unallocated_reward( mobile_rewards: &FileSinkClient, unallocated_type: UnallocatedRewardType, unallocated_amount: u64, - reward_info: &'_ ResolvedSubDaoEpochRewardInfo, + reward_info: &'_ EpochRewardInfo, ) -> anyhow::Result<()> { if unallocated_amount > 0 { let unallocated_reward = proto::MobileRewardShare { diff --git a/mobile_verifier/src/service_provider/reward.rs b/mobile_verifier/src/service_provider/reward.rs index f38015751..1e41ce44e 100644 --- a/mobile_verifier/src/service_provider/reward.rs +++ b/mobile_verifier/src/service_provider/reward.rs @@ -1,6 +1,6 @@ use crate::reward_shares::dc_to_hnt_bones; use file_store::traits::TimestampEncode; -use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; +use mobile_config::sub_dao_epoch_reward_info::EpochRewardInfo; use rust_decimal::{Decimal, RoundingStrategy}; use rust_decimal_macros::dec; @@ -20,7 +20,7 @@ mod proto { pub struct ServiceProviderRewardInfos { coll: Vec, total_sp_allocation: Decimal, - reward_info: ResolvedSubDaoEpochRewardInfo, + reward_info: EpochRewardInfo, } // Represents a single Service Providers information for rewarding, @@ -54,7 +54,7 @@ impl ServiceProviderRewardInfos { promotions: ServiceProviderPromotions, total_sp_allocation: Decimal, // Bones hnt_bone_price: Decimal, // Price in Bones - reward_info: ResolvedSubDaoEpochRewardInfo, + reward_info: EpochRewardInfo, ) -> Self { let all_transfer = dc_sessions.all_transfer(); // DC @@ -136,7 +136,7 @@ impl RewardInfo { pub fn iter_rewards( &self, total_allocation: Decimal, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, ) -> Vec<(u64, proto::MobileRewardShare)> { let mut rewards = self.promo_rewards(total_allocation, reward_info); rewards.push(self.carrier_reward(total_allocation, reward_info)); @@ -146,7 +146,7 @@ impl RewardInfo { pub fn carrier_reward( &self, total_allocation: Decimal, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, ) -> (u64, proto::MobileRewardShare) { let amount = (total_allocation * self.realized_data_perc).to_u64_floored(); // Rewarded BONES @@ -168,7 +168,7 @@ impl RewardInfo { pub fn promo_rewards( &self, total_allocation: Decimal, - reward_info: &ResolvedSubDaoEpochRewardInfo, + reward_info: &EpochRewardInfo, ) -> Vec<(u64, proto::MobileRewardShare)> { if self.promotions.is_empty() { return vec![]; @@ -278,12 +278,9 @@ mod tests { pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; - pub fn default_rewards_info( - total_emissions: u64, - epoch_duration: Duration, - ) -> ResolvedSubDaoEpochRewardInfo { + pub fn default_rewards_info(total_emissions: u64, epoch_duration: Duration) -> EpochRewardInfo { let now = Utc::now(); - ResolvedSubDaoEpochRewardInfo { + EpochRewardInfo { epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), diff --git a/mobile_verifier/src/telemetry.rs b/mobile_verifier/src/telemetry.rs index 9c3e209d9..90ab7fc6c 100644 --- a/mobile_verifier/src/telemetry.rs +++ b/mobile_verifier/src/telemetry.rs @@ -1,6 +1,6 @@ use crate::rewarder; use chrono::{DateTime, Utc}; -use mobile_config::EpochPeriod; +use mobile_config::EpochInfo; use sqlx::{Pool, Postgres}; const LAST_REWARDED_END_TIME: &str = "last_rewarded_end_time"; @@ -8,7 +8,7 @@ const DATA_TRANSFER_REWARDS_SCALE: &str = "data_transfer_rewards_scale"; pub async fn initialize(db: &Pool) -> anyhow::Result<()> { let next_reward_epoch = rewarder::next_reward_epoch(db).await?; - let epoch_period: EpochPeriod = next_reward_epoch.into(); + let epoch_period: EpochInfo = next_reward_epoch.into(); last_rewarded_end_time(epoch_period.period.start); Ok(()) } diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 69df84b61..aaa44efbb 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -24,7 +24,7 @@ use mobile_config::{ }; use mobile_config::client::sub_dao_client::SubDaoEpochRewardInfoResolver; -use mobile_config::sub_dao_epoch_reward_info::ResolvedSubDaoEpochRewardInfo; +use mobile_config::sub_dao_epoch_reward_info::EpochRewardInfo; use mobile_verifier::{ boosting_oracles::AssignedCoverageObjects, GatewayResolution, GatewayResolver, }; @@ -46,7 +46,7 @@ pub struct MockHexBoostingClient { #[derive(Debug, Clone)] pub struct MockSubDaoRewardsClient { - info: Option, + info: Option, } impl MockHexBoostingClient { @@ -79,7 +79,7 @@ impl SubDaoEpochRewardInfoResolver for MockSubDaoRewardsClient { &self, _sub_dao: &str, _epoch: u64, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { Ok(self.info.clone()) } } @@ -392,12 +392,9 @@ impl GatewayResolver for GatewayClientAllOwnersValid { } } -pub fn default_rewards_info( - total_emissions: u64, - epoch_duration: Duration, -) -> ResolvedSubDaoEpochRewardInfo { +pub fn default_rewards_info(total_emissions: u64, epoch_duration: Duration) -> EpochRewardInfo { let now = Utc::now(); - ResolvedSubDaoEpochRewardInfo { + EpochRewardInfo { epoch_day: 1, epoch_address: EPOCH_ADDRESS.into(), sub_dao_address: SUB_DAO_ADDRESS.into(), diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index 133c5375d..26d9348cd 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -21,7 +21,7 @@ use mobile_verifier::{ cell_type::CellType, coverage::CoverageObject, heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, - radio_threshold, reward_shares, rewarder, speedtests, HntPrice, + radio_threshold, reward_shares, rewarder, speedtests, PriceInfo, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -141,9 +141,9 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { .unwrap(); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -153,7 +153,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -332,9 +332,9 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -344,7 +344,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards(&mut mobile_rewards) ); @@ -499,9 +499,9 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -511,7 +511,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -678,9 +678,9 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -690,7 +690,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards(&mut mobile_rewards) ); @@ -814,9 +814,9 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: .unwrap(); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -826,7 +826,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -998,9 +998,9 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( .unwrap(); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1010,7 +1010,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, @@ -1207,9 +1207,9 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an .unwrap(); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1219,7 +1219,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_maybe_unallocated( &mut mobile_rewards, diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index 159be7a60..f0d1fd6a1 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -17,7 +17,7 @@ use mobile_verifier::{ heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, reward_shares, rewarder, sp_boosted_rewards_bans::{self, BannedRadioReport}, - speedtests, unique_connections, HntPrice, + speedtests, unique_connections, PriceInfo, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -62,9 +62,9 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); // todo: rebalance the tests to use a normalised hnt price - let hnt_price = HntPrice::new(10000000000000000, 8); - assert_eq!(hnt_price.hnt_price, dec!(100000000)); - assert_eq!(hnt_price.price_per_hnt_bone, dec!(1)); + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -74,7 +74,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { &mobile_rewards_client, &speedtest_avg_client, &reward_info, - hnt_price + price_info ), receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 3, false) ); From 82574fcbfb6bf3f960255790b72a7b75286de0ea Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 16 Dec 2024 12:33:05 +0000 Subject: [PATCH 21/36] rebase artifacts --- Cargo.lock | 53 +++++++------------ Cargo.toml | 4 +- iot_verifier/src/reward_share.rs | 1 - iot_verifier/src/rewarder.rs | 2 - mobile_verifier/src/reward_shares.rs | 4 +- mobile_verifier/src/rewarder.rs | 4 +- .../tests/integrations/rewarder_poc_dc.rs | 32 ++++++----- 7 files changed, 44 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a89634a5d..11d603510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1619,7 +1619,7 @@ source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-sup dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "prost", "rand 0.8.5", "rand_chacha 0.3.0", @@ -1788,7 +1788,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -2630,7 +2630,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "notify", "serde", @@ -3212,7 +3212,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-literal", "http 0.2.11", "lazy_static", @@ -3794,7 +3794,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", + "helium-proto", "hex", "hex-literal", "itertools", @@ -3821,23 +3821,6 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#fffce9d335b1e5d74ffd5da27ddba6e60b6d9d7c" -dependencies = [ - "bytes", - "prost", - "prost-build", - "serde", - "serde_json", - "strum", - "strum_macros", - "tonic", - "tonic-build", -] - -[[package]] -name = "helium-proto" -version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#c5c67f5631b69ef696961995045c0a41f9a5b936" dependencies = [ "bytes", "prost", @@ -3891,7 +3874,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4307,7 +4290,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "humantime-serde", "metrics", @@ -4377,7 +4360,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -4419,7 +4402,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -4461,7 +4444,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http-serde", "humantime-serde", "iot-config", @@ -5050,7 +5033,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -5093,7 +5076,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "mobile-config", "prost", "rand 0.8.5", @@ -5129,7 +5112,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -5174,7 +5157,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-assignments", "hextree", "http-serde", @@ -5858,7 +5841,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5941,7 +5924,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6082,7 +6065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.5.0", + "heck 0.4.0", "itertools", "log", "multimap", @@ -6580,7 +6563,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "lazy_static", "metrics", diff --git a/Cargo.toml b/Cargo.toml index acac87a64..fae3f6697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # -# [patch.'https://github.com/helium/proto'] -# helium-proto = { path = "../../proto" } + [patch.'https://github.com/helium/proto'] + helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } diff --git a/iot_verifier/src/reward_share.rs b/iot_verifier/src/reward_share.rs index f35cdb55a..eeb7dfb4a 100644 --- a/iot_verifier/src/reward_share.rs +++ b/iot_verifier/src/reward_share.rs @@ -286,7 +286,6 @@ impl GatewayShares { start_period: reward_period.start.encode_timestamp(), end_period: reward_period.end.encode_timestamp(), reward: Some(ProtoReward::GatewayReward(gateway_reward)), - epoch: 0, // placeholder, todo: remove }, ) }) diff --git a/iot_verifier/src/rewarder.rs b/iot_verifier/src/rewarder.rs index e72f0bbd3..c3b886362 100644 --- a/iot_verifier/src/rewarder.rs +++ b/iot_verifier/src/rewarder.rs @@ -304,7 +304,6 @@ pub async fn reward_operational( start_period: reward_period.start.encode_timestamp(), end_period: reward_period.end.encode_timestamp(), reward: Some(ProtoReward::OperationalReward(op_fund_reward)), - epoch: 0, // placeholder, todo: remove }, [], ) @@ -368,7 +367,6 @@ async fn write_unallocated_reward( reward_type: unallocated_type as i32, amount: unallocated_amount, })), - epoch: 0, // placeholder, todo: remove }; rewards_sink.write(unallocated_reward, []).await?.await??; }; diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 6fb4b25db..1b160c9d6 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -2262,8 +2262,10 @@ mod test { let mut owner_rewards = HashMap::::new(); let duration = Duration::hours(1); let epoch = (now - duration)..now; + let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); - let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(&epoch); + let reward_shares = + DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); let unique_connection_counts = HashMap::from([(gw1.clone(), 42)]); for (_reward_amount, _mobile_reward_v1, mobile_reward_v2) in CoverageShares::new( &hex_coverage, diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 30771803d..54c31c473 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -11,7 +11,7 @@ use crate::{ sp_boosted_rewards_bans, speedtests, speedtests_average::SpeedtestAverages, subscriber_location, subscriber_verified_mapping_event, telemetry, unique_connections, - Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, PriceInfo + PriceInfo, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, }; use anyhow::bail; use chrono::{DateTime, TimeZone, Utc}; @@ -457,7 +457,7 @@ async fn reward_poc( let boosted_hexes = BoostedHexes::get_all(hex_service_client).await?; - let unique_connections = unique_connections::db::get(pool, reward_period).await?; + let unique_connections = unique_connections::db::get(pool, &reward_info.epoch_period).await?; let boosted_hex_eligibility = BoostedHexEligibility::new( radio_threshold::verified_radio_thresholds(pool, &reward_info.epoch_period).await?, diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index f0d1fd6a1..428c27c11 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::common::{ self, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext, }; -use chrono::{DateTime, Duration as ChronoDuration, Utc}; +use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ coverage::{CoverageObject as FSCoverageObject, KeyType, RadioHexSignalLevel}, speedtest::CellSpeedtest, @@ -150,29 +150,35 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let now = Utc::now(); - let epoch = (now - ChronoDuration::hours(24))..now; + + let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let pubkey: PublicKeyBinary = HOTSPOT_3.to_string().parse().unwrap(); // wifi hotspot // seed all the things let mut txn = pool.clone().begin().await?; - seed_heartbeats(epoch.start, &mut txn).await?; - seed_speedtests(epoch.end, &mut txn).await?; - seed_data_sessions(epoch.start, &mut txn).await?; + seed_heartbeats(reward_info.epoch_period.start, &mut txn).await?; + seed_speedtests(reward_info.epoch_period.end, &mut txn).await?; + seed_data_sessions(reward_info.epoch_period.start, &mut txn).await?; txn.commit().await?; update_assignments_bad(&pool).await?; // Run rewards with no unique connections, no poc rewards, expect unallocated let boosted_hexes = vec![]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); + + let price_info = PriceInfo::new(10000000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(100000000)); + assert_eq!(price_info.price_per_bone, dec!(1)); + let (_, _rewards) = tokio::join!( rewarder::reward_poc_and_dc( &pool, &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, - dec!(0.0001) + &reward_info, + price_info.clone() ), // expecting NO poc rewards, expecting unallocated receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 0, true) @@ -180,12 +186,12 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { // seed single unique conections report within epoch let mut txn = pool.begin().await?; - seed_unique_connections(&mut txn, &[(pubkey.clone(), 42)], &epoch).await?; + seed_unique_connections(&mut txn, &[(pubkey.clone(), 42)], &reward_info.epoch_period).await?; txn.commit().await?; // SP ban radio, unique connections should supersede banning let mut txn = pool.begin().await?; - ban_wifi_radio_for_epoch(&mut txn, pubkey.clone(), &epoch).await?; + ban_wifi_radio_for_epoch(&mut txn, pubkey.clone(), &reward_info.epoch_period).await?; txn.commit().await?; let (_, rewards) = tokio::join!( @@ -195,8 +201,8 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { &hex_boosting_client, &mobile_rewards_client, &speedtest_avg_client, - &epoch, - dec!(0.0001) + &reward_info, + price_info ), // expecting single radio with poc rewards, no unallocated receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 1, false) @@ -209,7 +215,7 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { let dc_sum: u64 = dc_rewards.iter().map(|r| r.dc_transfer_reward).sum(); let total = poc_sum + dc_sum; - let expected_sum = reward_shares::get_scheduled_tokens_for_poc(epoch.end - epoch.start) + let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() .unwrap(); assert_eq!(expected_sum, total); From f9e5c3aedde2af74471e94e003d6906a27bc7d72 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 16 Dec 2024 12:44:47 +0000 Subject: [PATCH 22/36] remove proto path usage --- Cargo.lock | 55 +++++++++++++++++++++++++++++++++++------------------- Cargo.toml | 4 ++-- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11d603510..41783cabb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1619,13 +1619,13 @@ source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-sup dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "prost", "rand 0.8.5", "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", ] @@ -1788,7 +1788,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -2630,7 +2630,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "notify", "serde", @@ -3212,7 +3212,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-literal", "http 0.2.11", "lazy_static", @@ -3794,7 +3794,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", "hex", "hex-literal", "itertools", @@ -3821,6 +3821,23 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" +dependencies = [ + "bytes", + "prost", + "prost-build", + "serde", + "serde_json", + "strum", + "strum_macros", + "tonic", + "tonic-build", +] + +[[package]] +name = "helium-proto" +version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" dependencies = [ "bytes", "prost", @@ -3874,7 +3891,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4290,7 +4307,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "humantime-serde", "metrics", @@ -4360,7 +4377,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -4402,7 +4419,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -4444,7 +4461,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http-serde", "humantime-serde", "iot-config", @@ -5033,7 +5050,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -5076,7 +5093,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "mobile-config", "prost", "rand 0.8.5", @@ -5112,7 +5129,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -5157,7 +5174,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-assignments", "hextree", "http-serde", @@ -5841,7 +5858,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5924,7 +5941,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6563,7 +6580,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "lazy_static", "metrics", @@ -9990,7 +10007,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", "twox-hash", "xorf", diff --git a/Cargo.toml b/Cargo.toml index fae3f6697..acac87a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # - [patch.'https://github.com/helium/proto'] - helium-proto = { path = "../../proto" } +# [patch.'https://github.com/helium/proto'] +# helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } From 04853310b8eeca6d16bb5e217cd2703a15253665 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 16 Dec 2024 14:04:54 +0000 Subject: [PATCH 23/36] drop placeholder column usage --- Cargo.lock | 53 +++++++------------ Cargo.toml | 4 +- .../src/sub_dao_epoch_reward_info.rs | 10 ++-- 3 files changed, 25 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41783cabb..0e2667239 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1619,7 +1619,7 @@ source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-sup dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "prost", "rand 0.8.5", "rand_chacha 0.3.0", @@ -1788,7 +1788,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -2630,7 +2630,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "notify", "serde", @@ -3212,7 +3212,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-literal", "http 0.2.11", "lazy_static", @@ -3794,7 +3794,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", + "helium-proto", "hex", "hex-literal", "itertools", @@ -3821,23 +3821,6 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" -dependencies = [ - "bytes", - "prost", - "prost-build", - "serde", - "serde_json", - "strum", - "strum_macros", - "tonic", - "tonic-build", -] - -[[package]] -name = "helium-proto" -version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" dependencies = [ "bytes", "prost", @@ -3891,7 +3874,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4307,7 +4290,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "humantime-serde", "metrics", @@ -4377,7 +4360,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -4419,7 +4402,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -4461,7 +4444,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http-serde", "humantime-serde", "iot-config", @@ -5050,7 +5033,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -5093,7 +5076,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "mobile-config", "prost", "rand 0.8.5", @@ -5129,7 +5112,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -5174,7 +5157,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-assignments", "hextree", "http-serde", @@ -5858,7 +5841,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5941,7 +5924,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6082,7 +6065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.4.0", + "heck 0.5.0", "itertools", "log", "multimap", @@ -6580,7 +6563,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "lazy_static", "metrics", diff --git a/Cargo.toml b/Cargo.toml index acac87a64..fae3f6697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # -# [patch.'https://github.com/helium/proto'] -# helium-proto = { path = "../../proto" } + [patch.'https://github.com/helium/proto'] + helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index 1481ed22b..ce81a9295 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -20,7 +20,7 @@ pub struct RawSubDaoEpochRewardInfo { epoch: u64, epoch_address: String, sub_dao_address: String, - rewards_issued: u64, + hnt_rewards_issued: u64, delegation_rewards_issued: u64, rewards_issued_at: DateTime, } @@ -37,7 +37,7 @@ impl From for SubDaoEpochRewardInfoProto { epoch: info.epoch, epoch_address: info.epoch_address, sub_dao_address: info.sub_dao_address, - rewards_issued: info.rewards_issued, + hnt_rewards_issued: info.hnt_rewards_issued, delegation_rewards_issued: info.delegation_rewards_issued, rewards_issued_at: info.rewards_issued_at.encode_timestamp(), } @@ -49,7 +49,7 @@ impl TryFrom for EpochRewardInfo { fn try_from(info: SubDaoEpochRewardInfoProto) -> Result { let epoch_period: EpochInfo = info.epoch.into(); - let epoch_rewards = Decimal::from(info.rewards_issued + info.delegation_rewards_issued); + let epoch_rewards = Decimal::from(info.hnt_rewards_issued + info.delegation_rewards_issued); Ok(Self { epoch_day: info.epoch, @@ -73,7 +73,7 @@ pub(crate) mod db { address AS epoch_address, sub_dao AS sub_dao_address, epoch::BIGINT, - delegation_rewards_issued::BIGINT AS rewards_issued, + hnt_rewards_issued::BIGINT, delegation_rewards_issued::BIGINT, rewards_issued_at::BIGINT FROM sub_dao_epoch_infos @@ -108,7 +108,7 @@ pub(crate) mod db { epoch: row.get::("epoch") as u64, epoch_address: row.get::("epoch_address"), sub_dao_address: row.get::("sub_dao_address"), - rewards_issued: row.get::("rewards_issued") as u64, + hnt_rewards_issued: row.get::("hnt_rewards_issued") as u64, delegation_rewards_issued: row.get::("delegation_rewards_issued") as u64, rewards_issued_at, }) From 571c2fac67d13cdb2f1fbf1fc7b5d242e14a96d9 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 16 Dec 2024 14:48:20 +0000 Subject: [PATCH 24/36] remove proto patch again --- Cargo.lock | 57 +++++++++++++++++++++++++++++++++++------------------- Cargo.toml | 4 ++-- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e2667239..8cac0dc9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,17 +1615,17 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#17d048a7444ccde5e1c24001aa07956abd218cb3" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#57e59d25ca7ae2e7ae84174842aaa50fbdd5ca74" dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "prost", "rand 0.8.5", "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", ] @@ -1788,7 +1788,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -2630,7 +2630,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "notify", "serde", @@ -3212,7 +3212,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-literal", "http 0.2.11", "lazy_static", @@ -3794,7 +3794,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", "hex", "hex-literal", "itertools", @@ -3821,6 +3821,23 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#57e59d25ca7ae2e7ae84174842aaa50fbdd5ca74" +dependencies = [ + "bytes", + "prost", + "prost-build", + "serde", + "serde_json", + "strum", + "strum_macros", + "tonic", + "tonic-build", +] + +[[package]] +name = "helium-proto" +version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" dependencies = [ "bytes", "prost", @@ -3874,7 +3891,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4290,7 +4307,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "humantime-serde", "metrics", @@ -4360,7 +4377,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -4402,7 +4419,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -4444,7 +4461,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http-serde", "humantime-serde", "iot-config", @@ -5033,7 +5050,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -5076,7 +5093,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "mobile-config", "prost", "rand 0.8.5", @@ -5112,7 +5129,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -5157,7 +5174,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-assignments", "hextree", "http-serde", @@ -5841,7 +5858,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5924,7 +5941,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6563,7 +6580,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "lazy_static", "metrics", @@ -9990,7 +10007,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", "twox-hash", "xorf", diff --git a/Cargo.toml b/Cargo.toml index fae3f6697..acac87a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # - [patch.'https://github.com/helium/proto'] - helium-proto = { path = "../../proto" } +# [patch.'https://github.com/helium/proto'] +# helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } From 8578ec64235759d36d64a726e91a9bc2407f35a1 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 16 Dec 2024 16:40:48 +0000 Subject: [PATCH 25/36] tidy up --- .../tests/integrations/rewarder_sp_rewards.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs index edaeddf2e..0eecc8074 100644 --- a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs +++ b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::string::ToString; use async_trait::async_trait; -use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; +use chrono::{DateTime, Duration, Utc}; use helium_proto::{ service_provider_promotions::Promotion, services::poc_mobile::{ @@ -289,7 +289,7 @@ async fn seed_hotspot_data( upload_bytes: 1024 * 1000, download_bytes: 1024 * 10000, num_dcs: 10_000, - received_timestamp: ts - ChronoDuration::hours(1), + received_timestamp: ts - Duration::hours(1), }; let data_session_2 = data_session::HotspotDataSession { @@ -298,7 +298,7 @@ async fn seed_hotspot_data( upload_bytes: 1024 * 1000, download_bytes: 1024 * 50000, num_dcs: 50_000, - received_timestamp: ts - ChronoDuration::hours(2), + received_timestamp: ts - Duration::hours(2), }; data_session_1.save(txn).await?; @@ -316,7 +316,7 @@ async fn seed_hotspot_data_invalid_sp( upload_bytes: 1024 * 1000, download_bytes: 1024 * 10000, num_dcs: 10_000, - received_timestamp: ts - ChronoDuration::hours(2), + received_timestamp: ts - Duration::hours(2), }; let data_session_2 = data_session::HotspotDataSession { @@ -325,7 +325,7 @@ async fn seed_hotspot_data_invalid_sp( upload_bytes: 1024 * 1000, download_bytes: 1024 * 50000, num_dcs: 50_000, - received_timestamp: ts - ChronoDuration::hours(2), + received_timestamp: ts - Duration::hours(2), }; data_session_1.save(txn).await?; From 62821206ce48b3f9fbda338bca2e03bd109f8fc0 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 17 Dec 2024 12:58:04 +0000 Subject: [PATCH 26/36] fix failing test, default hnt token price to equate to same prior per mobile bone price --- .../tests/integrations/hex_boosting.rs | 49 ++++++++----------- .../tests/integrations/rewarder_poc_dc.rs | 47 +++++++++++------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index 26d9348cd..a6547bed6 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -140,10 +140,9 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { .to_u64() .unwrap(); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -331,10 +330,9 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -498,10 +496,9 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -677,10 +674,9 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -813,10 +809,9 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: .to_u64() .unwrap(); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -997,10 +992,9 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( .to_u64() .unwrap(); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1206,10 +1200,9 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an .to_u64() .unwrap(); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index 428c27c11..660f06342 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -33,7 +33,7 @@ pub mod proto { CoverageObjectValidity, GatewayReward, HeartbeatValidity, LocationSource, MobileRewardShare, RadioRewardV2, SeniorityUpdateReason, ServiceProviderBoostedRewardsBannedRadioIngestReportV1, - ServiceProviderBoostedRewardsBannedRadioReqV1, SignalLevel, + ServiceProviderBoostedRewardsBannedRadioReqV1, SignalLevel, UnallocatedReward, }; } @@ -61,10 +61,9 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -76,12 +75,12 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { &reward_info, price_info ), - receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 3, false) + receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 3, true) ); - if let Ok((poc_rewards, dc_rewards)) = rewards { + if let Ok((poc_rewards, dc_rewards, unallocated_reward)) = rewards { // assert poc reward outputs - let hotspot_1_reward = 9_784_735_514_514; - let hotspot_2_reward = 39_138_942_058_056; + let hotspot_1_reward = 9_784_735_514_513; + let hotspot_2_reward = 39_138_942_058_055; let hotspot_3_reward = 391_389_420_580; assert_eq!(hotspot_1_reward, poc_rewards[0].total_poc_reward()); assert_eq!( @@ -99,6 +98,10 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { PublicKeyBinary::from(poc_rewards[2].hotspot_key.clone()).to_string() ); + // assert the unallocated reward + let unallocated_reward = unallocated_reward.unwrap(); + assert_eq!(unallocated_reward.amount, 2); + // assert the boosted hexes in the radio rewards // boosted hexes will contain the used multiplier for each boosted hex // in this test there are no boosted hexes @@ -126,7 +129,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { // confirm the total rewards allocated matches expectations let poc_sum: u64 = poc_rewards.iter().map(|r| r.total_poc_reward()).sum(); let dc_sum: u64 = dc_rewards.iter().map(|r| r.dc_transfer_reward).sum(); - let total = poc_sum + dc_sum; + let total = poc_sum + dc_sum + unallocated_reward.amount; let expected_sum = reward_shares::get_scheduled_tokens_for_poc(reward_info.epoch_emissions) .to_u64() @@ -167,9 +170,9 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { let boosted_hexes = vec![]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let price_info = PriceInfo::new(10000000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(100000000)); - assert_eq!(price_info.price_per_bone, dec!(1)); + let price_info = PriceInfo::new(1000000000000, 8); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); let (_, _rewards) = tokio::join!( rewarder::reward_poc_and_dc( @@ -207,7 +210,7 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { // expecting single radio with poc rewards, no unallocated receive_expected_rewards_with_counts(&mut mobile_rewards, 3, 1, false) ); - let Ok((poc_rewards, dc_rewards)) = rewards else { + let Ok((poc_rewards, dc_rewards, _unallocated_reward)) = rewards else { panic!("rewards failed"); }; @@ -228,7 +231,11 @@ async fn receive_expected_rewards_with_counts( expected_dc_reward_count: usize, expected_poc_reward_count: usize, expect_unallocated: bool, -) -> anyhow::Result<(Vec, Vec)> { +) -> anyhow::Result<( + Vec, + Vec, + Option, +)> { let mut dc_rewards = vec![]; let mut poc_rewards = vec![]; @@ -240,14 +247,16 @@ async fn receive_expected_rewards_with_counts( poc_rewards.push(mobile_rewards.receive_radio_reward().await); } - if expect_unallocated { - mobile_rewards.receive_unallocated_reward().await; - } + let unallocated_reward = if expect_unallocated { + Some(mobile_rewards.receive_unallocated_reward().await) + } else { + None + }; dc_rewards.sort_by(|a, b| b.hotspot_key.cmp(&a.hotspot_key)); poc_rewards.sort_by(|a, b| b.hotspot_key.cmp(&a.hotspot_key)); - Ok((poc_rewards, dc_rewards)) + Ok((poc_rewards, dc_rewards, unallocated_reward)) } async fn seed_heartbeats( From 029838018bf1934628362bc32da6d47e68030bfc Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 17 Dec 2024 15:18:13 +0000 Subject: [PATCH 27/36] tidy up --- mobile_verifier/src/reward_shares.rs | 78 ++++++++++--------- .../tests/integrations/common/mod.rs | 11 ++- .../tests/integrations/hex_boosting.rs | 33 +++----- .../tests/integrations/rewarder_poc_dc.rs | 13 ++-- 4 files changed, 67 insertions(+), 68 deletions(-) diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index 1b160c9d6..c71a9654d 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -791,7 +791,6 @@ fn eligible_for_coverage_map( #[cfg(test)] mod test { - use super::*; use hex_assignments::{assignment::HexAssignments, Assignment}; @@ -812,6 +811,7 @@ mod test { use chrono::{Duration, Utc}; use file_store::speedtest::CellSpeedtest; use futures::stream::{self, BoxStream}; + use helium_lib::token::Token; use helium_proto::{ services::poc_mobile::mobile_reward_share::Reward as MobileReward, ServiceProvider, }; @@ -820,8 +820,11 @@ mod test { use std::collections::HashMap; use uuid::Uuid; - pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; - pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; + const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; + + const EMISSIONS_POOL_24_HOURS: u64 = 82_191_780_821_917; + const EMISSIONS_POOL_1_HOUR: u64 = 3_424_657_534_247; fn hex_assignments_mock() -> HexAssignments { HexAssignments { @@ -862,6 +865,11 @@ mod test { } } + fn default_price_info() -> PriceInfo { + let token = Token::Hnt; + PriceInfo::new(10000000000000000, token.decimals()) + } + #[test] fn test_poc_scheduled_tokens() { let rewards_info = default_rewards_info(100_000_000_000_000, Duration::hours(1)); @@ -890,6 +898,20 @@ mod test { assert_eq!(dec!(4_000_000_000_000), v); } + #[test] + fn test_price_conversion() { + let token = Token::Hnt; + let hnt_dollar_price = dec!(1.0); + let hnt_price_from_pricer = 100000000_u64; + let hnt_dollar_bone_price = dec!(0.00000001); + + let hnt_price = PriceInfo::new(hnt_price_from_pricer, token.decimals()); + + assert_eq!(hnt_dollar_bone_price, hnt_price.price_per_bone); + assert_eq!(hnt_price_from_pricer, hnt_price.price_in_bones); + assert_eq!(hnt_dollar_price, hnt_price.price_per_token); + } + #[tokio::test] async fn subscriber_rewards() { const NUM_SUBSCRIBERS: u64 = 10_000; @@ -910,7 +932,7 @@ mod test { } // set our rewards info - let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); // translate location shares into shares let shares = MapperShares::new(location_shares, vsme_shares); @@ -988,7 +1010,7 @@ mod test { }, ); - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let total_rewards = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions); @@ -1002,8 +1024,7 @@ mod test { let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new(rewards_info.epoch_emissions); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); + let price_info = default_price_info(); assert_eq!(price_info.price_per_token, dec!(100000000)); assert_eq!(price_info.price_per_bone, dec!(1)); @@ -1053,10 +1074,9 @@ mod test { .unwrap(); // set our rewards info - let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); - // todo: rebalance the tests to use a normalised hnt price - let price_info = PriceInfo::new(10000000000000000, 8); + let price_info = default_price_info(); assert_eq!(price_info.price_per_token, dec!(100000000)); assert_eq!(price_info.price_per_bone, dec!(1)); @@ -1269,7 +1289,7 @@ mod test { let speedtest_avgs = SpeedtestAverages { averages }; - let rewards_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -1671,7 +1691,7 @@ mod test { // calculate the rewards for the sample group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -1857,7 +1877,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -1994,7 +2014,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2131,7 +2151,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2262,7 +2282,7 @@ mod test { let mut owner_rewards = HashMap::::new(); let duration = Duration::hours(1); let epoch = (now - duration)..now; - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2321,7 +2341,7 @@ mod test { let now = Utc::now(); // We should never see any radio shares from owner2, since all of them are // less than or equal to zero. - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let uuid_1 = Uuid::new_v4(); let uuid_2 = Uuid::new_v4(); @@ -2436,7 +2456,7 @@ mod test { #[tokio::test] async fn skip_empty_radio_rewards() { - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let coverage_shares = CoverageShares { coverage_map: coverage_map::CoverageMapBuilder::default() .build(&BoostedHexes::default(), rewards_info.epoch_period.start), @@ -2456,7 +2476,7 @@ mod test { let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let total_sp_rewards = service_provider::get_scheduled_tokens(rewards_info.epoch_emissions); let sp_reward_infos = ServiceProviderRewardInfos::new( @@ -2496,7 +2516,7 @@ mod test { let hnt_bone_price = dec!(1.0); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let total_sp_rewards_in_bones = dec!(1_0000_0000); let total_rewards_value_in_dc = hnt_bones_to_dc(total_sp_rewards_in_bones, hnt_bone_price); @@ -2543,7 +2563,7 @@ mod test { let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); @@ -2587,7 +2607,7 @@ mod test { let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(3_424_657_534_247, Duration::hours(24)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(24)); let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); let sp_reward_infos = ServiceProviderRewardInfos::new( @@ -2623,18 +2643,4 @@ mod test { .unwrap_or(0); assert_eq!(unallocated_sp_reward_amount, 0); } - - #[test] - fn test_price_conversion() { - let hnt_dollar_price = dec!(1.0); - let hnt_price_from_pricer = 100000000_u64; - let hnt_dollar_bone_price = dec!(0.00000001); - - let pricer_decimals = 8; - let hnt_price = PriceInfo::new(hnt_price_from_pricer, pricer_decimals); - - assert_eq!(hnt_dollar_bone_price, hnt_price.price_per_bone); - assert_eq!(hnt_price_from_pricer, hnt_price.price_in_bones); - assert_eq!(hnt_dollar_price, hnt_price.price_per_token); - } } diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index aaa44efbb..fcd53116b 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -23,10 +23,11 @@ use mobile_config::{ }, }; +use helium_lib::token::Token; use mobile_config::client::sub_dao_client::SubDaoEpochRewardInfoResolver; use mobile_config::sub_dao_epoch_reward_info::EpochRewardInfo; use mobile_verifier::{ - boosting_oracles::AssignedCoverageObjects, GatewayResolution, GatewayResolver, + boosting_oracles::AssignedCoverageObjects, GatewayResolution, GatewayResolver, PriceInfo, }; use rust_decimal::{prelude::ToPrimitive, Decimal}; use rust_decimal_macros::dec; @@ -403,3 +404,11 @@ pub fn default_rewards_info(total_emissions: u64, epoch_duration: Duration) -> E rewards_issued_at: now, } } + +pub fn default_price_info() -> PriceInfo { + let token = Token::Hnt; + let price_info = PriceInfo::new(1000000000000, token.decimals()); + assert_eq!(price_info.price_per_token, dec!(10000)); + assert_eq!(price_info.price_per_bone, dec!(0.0001)); + price_info +} diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index a6547bed6..54a56153c 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -1,5 +1,6 @@ use crate::common::{ - self, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext, + self, default_price_info, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, + RadioRewardV2Ext, }; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ @@ -21,7 +22,7 @@ use mobile_verifier::{ cell_type::CellType, coverage::CoverageObject, heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, - radio_threshold, reward_shares, rewarder, speedtests, PriceInfo, + radio_threshold, reward_shares, rewarder, speedtests, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -140,9 +141,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { .to_u64() .unwrap(); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -330,9 +329,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -496,9 +493,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -674,9 +669,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -809,9 +802,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: .to_u64() .unwrap(); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -992,9 +983,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( .to_u64() .unwrap(); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -1200,9 +1189,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an .to_u64() .unwrap(); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index 660f06342..4addb3007 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -1,7 +1,8 @@ use std::ops::Range; use crate::common::{ - self, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, RadioRewardV2Ext, + self, default_price_info, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, + RadioRewardV2Ext, }; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ @@ -17,7 +18,7 @@ use mobile_verifier::{ heartbeats::{HbType, Heartbeat, ValidatedHeartbeat}, reward_shares, rewarder, sp_boosted_rewards_bans::{self, BannedRadioReport}, - speedtests, unique_connections, PriceInfo, + speedtests, unique_connections, }; use rust_decimal::prelude::*; use rust_decimal_macros::dec; @@ -61,9 +62,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, rewards) = tokio::join!( // run rewards for poc and dc @@ -170,9 +169,7 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { let boosted_hexes = vec![]; let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let price_info = PriceInfo::new(1000000000000, 8); - assert_eq!(price_info.price_per_token, dec!(10000)); - assert_eq!(price_info.price_per_bone, dec!(0.0001)); + let price_info = default_price_info(); let (_, _rewards) = tokio::join!( rewarder::reward_poc_and_dc( From d017240445b8c600f03287998e9e1a71b6f7b148 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 17 Dec 2024 16:11:13 +0000 Subject: [PATCH 28/36] centralise emission values --- .../src/sub_dao_epoch_reward_info.rs | 2 +- mobile_verifier/src/reward_shares.rs | 45 ++++++++++--------- .../tests/integrations/common/mod.rs | 9 ++-- .../tests/integrations/hex_boosting.rs | 16 +++---- .../tests/integrations/rewarder_mappers.rs | 8 ++-- .../tests/integrations/rewarder_poc_dc.rs | 6 +-- .../tests/integrations/rewarder_sp_rewards.rs | 12 ++--- 7 files changed, 53 insertions(+), 45 deletions(-) diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index ce81a9295..b356c9566 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -93,7 +93,7 @@ pub(crate) mod db { .bind(sub_dao_address) .fetch_optional(db) .await?; - tracing::info!("get_info: {:?}", res); + tracing::debug!("get_info: {:?}", res); Ok(res) } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index c71a9654d..e23a19bda 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -823,8 +823,8 @@ mod test { const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; - const EMISSIONS_POOL_24_HOURS: u64 = 82_191_780_821_917; - const EMISSIONS_POOL_1_HOUR: u64 = 3_424_657_534_247; + const EMISSIONS_POOL_IN_BONES_24_HOURS: u64 = 82_191_780_821_917; + const EMISSIONS_POOL_IN_BONES_1_HOUR: u64 = 3_424_657_534_247; fn hex_assignments_mock() -> HexAssignments { HexAssignments { @@ -866,8 +866,7 @@ mod test { } fn default_price_info() -> PriceInfo { - let token = Token::Hnt; - PriceInfo::new(10000000000000000, token.decimals()) + PriceInfo::new(10000000000000000, Token::Hnt.decimals()) } #[test] @@ -932,7 +931,8 @@ mod test { } // set our rewards info - let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); + let rewards_info = + default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); // translate location shares into shares let shares = MapperShares::new(location_shares, vsme_shares); @@ -1010,7 +1010,7 @@ mod test { }, ); - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let total_rewards = get_scheduled_tokens_for_poc(rewards_info.epoch_emissions); @@ -1074,7 +1074,8 @@ mod test { .unwrap(); // set our rewards info - let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); + let rewards_info = + default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let price_info = default_price_info(); assert_eq!(price_info.price_per_token, dec!(100000000)); @@ -1289,7 +1290,8 @@ mod test { let speedtest_avgs = SpeedtestAverages { averages }; - let rewards_info = default_rewards_info(EMISSIONS_POOL_24_HOURS, Duration::hours(24)); + let rewards_info = + default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -1691,7 +1693,7 @@ mod test { // calculate the rewards for the sample group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -1877,7 +1879,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2014,7 +2016,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2151,7 +2153,7 @@ mod test { // calculate the rewards for the group let mut owner_rewards = HashMap::::new(); - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2282,7 +2284,7 @@ mod test { let mut owner_rewards = HashMap::::new(); let duration = Duration::hours(1); let epoch = (now - duration)..now; - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let reward_shares = DataTransferAndPocAllocatedRewardBuckets::new_poc_only(rewards_info.epoch_emissions); @@ -2341,7 +2343,7 @@ mod test { let now = Utc::now(); // We should never see any radio shares from owner2, since all of them are // less than or equal to zero. - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let uuid_1 = Uuid::new_v4(); let uuid_2 = Uuid::new_v4(); @@ -2456,7 +2458,7 @@ mod test { #[tokio::test] async fn skip_empty_radio_rewards() { - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let coverage_shares = CoverageShares { coverage_map: coverage_map::CoverageMapBuilder::default() .build(&BoostedHexes::default(), rewards_info.epoch_period.start), @@ -2476,7 +2478,7 @@ mod test { let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let total_sp_rewards = service_provider::get_scheduled_tokens(rewards_info.epoch_emissions); let sp_reward_infos = ServiceProviderRewardInfos::new( @@ -2516,7 +2518,7 @@ mod test { let hnt_bone_price = dec!(1.0); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let total_sp_rewards_in_bones = dec!(1_0000_0000); let total_rewards_value_in_dc = hnt_bones_to_dc(total_sp_rewards_in_bones, hnt_bone_price); @@ -2559,11 +2561,11 @@ mod test { #[test] fn service_provider_reward_hip87_ex1() { - // hnt price from hip example and converted to bones + // price from hip example and converted to bones let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(1)); + let rewards_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(1)); let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); @@ -2603,11 +2605,12 @@ mod test { #[test] fn service_provider_reward_hip87_ex2() { - // hnt price from hip example and converted to bones + // price from hip example and converted to bones let hnt_bone_price = dec!(0.0001) / dec!(1_0000_0000); let sp1 = ServiceProvider::HeliumMobile; - let rewards_info = default_rewards_info(EMISSIONS_POOL_1_HOUR, Duration::hours(24)); + let rewards_info = + default_rewards_info(EMISSIONS_POOL_IN_BONES_1_HOUR, Duration::hours(24)); let total_sp_rewards_in_bones = dec!(500_000_000) * dec!(1_0000_0000); let sp_reward_infos = ServiceProviderRewardInfos::new( diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index fcd53116b..aaeea9e60 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -5,6 +5,7 @@ use file_store::{ }; use futures::{stream, StreamExt}; use helium_crypto::PublicKeyBinary; +use helium_lib::token::Token; use helium_proto::services::{ mobile_config::NetworkKeyRole, poc_mobile::{ @@ -17,15 +18,13 @@ use helium_proto::services::{ use hex_assignments::{Assignment, HexAssignment, HexBoostData}; use mobile_config::{ boosted_hex_info::{BoostedHexInfo, BoostedHexInfoStream}, + client::sub_dao_client::SubDaoEpochRewardInfoResolver, client::{ authorization_client::AuthorizationVerifier, entity_client::EntityVerifier, hex_boosting_client::HexBoostingInfoResolver, ClientError, }, + sub_dao_epoch_reward_info::EpochRewardInfo, }; - -use helium_lib::token::Token; -use mobile_config::client::sub_dao_client::SubDaoEpochRewardInfoResolver; -use mobile_config::sub_dao_epoch_reward_info::EpochRewardInfo; use mobile_verifier::{ boosting_oracles::AssignedCoverageObjects, GatewayResolution, GatewayResolver, PriceInfo, }; @@ -39,6 +38,8 @@ use tonic::async_trait; pub const EPOCH_ADDRESS: &str = "112E7TxoNHV46M6tiPA8N1MkeMeQxc9ztb4JQLXBVAAUfq1kJLoF"; pub const SUB_DAO_ADDRESS: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; +pub const EMISSIONS_POOL_IN_BONES_24_HOURS: u64 = 82_191_780_821_917; + #[derive(Debug, Clone)] #[allow(dead_code)] pub struct MockHexBoostingClient { diff --git a/mobile_verifier/tests/integrations/hex_boosting.rs b/mobile_verifier/tests/integrations/hex_boosting.rs index 54a56153c..4ebb0a0a9 100644 --- a/mobile_verifier/tests/integrations/hex_boosting.rs +++ b/mobile_verifier/tests/integrations/hex_boosting.rs @@ -1,6 +1,6 @@ use crate::common::{ self, default_price_info, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, - RadioRewardV2Ext, + RadioRewardV2Ext, EMISSIONS_POOL_IN_BONES_24_HOURS, }; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ @@ -57,7 +57,7 @@ async fn test_poc_with_boosted_hexes(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); @@ -327,7 +327,7 @@ async fn test_poc_boosted_hexes_thresholds_not_met(pool: PgPool) -> anyhow::Resu let hex_boosting_client = MockHexBoostingClient::new(boosted_hexes); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let price_info = default_price_info(); @@ -395,7 +395,7 @@ async fn test_poc_with_multi_coverage_boosted_hexes(pool: PgPool) -> anyhow::Res let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); @@ -613,7 +613,7 @@ async fn test_expired_boosted_hex(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things @@ -736,7 +736,7 @@ async fn test_reduced_location_score_with_boosted_hexes(pool: PgPool) -> anyhow: let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things @@ -914,7 +914,7 @@ async fn test_distance_from_asserted_removes_boosting_but_not_location_trust( let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); // seed all the things @@ -1093,7 +1093,7 @@ async fn test_poc_with_cbrs_and_multi_coverage_boosted_hexes(pool: PgPool) -> an let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let boost_period_length = Duration::days(30); diff --git a/mobile_verifier/tests/integrations/rewarder_mappers.rs b/mobile_verifier/tests/integrations/rewarder_mappers.rs index a7883da6c..6162fea78 100644 --- a/mobile_verifier/tests/integrations/rewarder_mappers.rs +++ b/mobile_verifier/tests/integrations/rewarder_mappers.rs @@ -1,4 +1,6 @@ -use crate::common::{self, default_rewards_info, MockFileSinkReceiver}; +use crate::common::{ + self, default_rewards_info, MockFileSinkReceiver, EMISSIONS_POOL_IN_BONES_24_HOURS, +}; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ mobile_subscriber::{SubscriberLocationIngestReport, SubscriberLocationReq}, @@ -29,7 +31,7 @@ const HOTSPOT_1: &str = "112NqN2WWMwtK29PMzRby62fDydBJfsCLkCAf392stdok48ovNT6"; async fn test_mapper_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); // seed db let mut txn = pool.clone().begin().await?; @@ -108,7 +110,7 @@ async fn test_subscriber_can_only_earn_verification_mapping_if_earned_disco_mapp ) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let mut txn = pool.begin().await?; let sub_loc_report = SubscriberLocationIngestReport { diff --git a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs index 4addb3007..8a8ffb1c1 100644 --- a/mobile_verifier/tests/integrations/rewarder_poc_dc.rs +++ b/mobile_verifier/tests/integrations/rewarder_poc_dc.rs @@ -2,7 +2,7 @@ use std::ops::Range; use crate::common::{ self, default_price_info, default_rewards_info, MockFileSinkReceiver, MockHexBoostingClient, - RadioRewardV2Ext, + RadioRewardV2Ext, EMISSIONS_POOL_IN_BONES_24_HOURS, }; use chrono::{DateTime, Duration as ChronoDuration, Duration, Utc}; use file_store::{ @@ -48,7 +48,7 @@ async fn test_poc_and_dc_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); // seed all the things let mut txn = pool.clone().begin().await?; @@ -153,7 +153,7 @@ async fn test_qualified_wifi_poc_rewards(pool: PgPool) -> anyhow::Result<()> { let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); let (speedtest_avg_client, _speedtest_avg_server) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let pubkey: PublicKeyBinary = HOTSPOT_3.to_string().parse().unwrap(); // wifi hotspot diff --git a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs index 0eecc8074..7c66ec444 100644 --- a/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs +++ b/mobile_verifier/tests/integrations/rewarder_sp_rewards.rs @@ -14,7 +14,9 @@ use rust_decimal::prelude::*; use rust_decimal_macros::dec; use sqlx::{PgPool, Postgres, Transaction}; -use crate::common::{self, default_rewards_info, MockFileSinkReceiver}; +use crate::common::{ + self, default_rewards_info, MockFileSinkReceiver, EMISSIONS_POOL_IN_BONES_24_HOURS, +}; use mobile_config::client::{carrier_service_client::CarrierServiceVerifier, ClientError}; use mobile_verifier::{data_session, reward_shares, rewarder, service_provider}; @@ -75,7 +77,7 @@ async fn test_service_provider_rewards(pool: PgPool) -> anyhow::Result<()> { let carrier_client = MockCarrierServiceClient::new(valid_sps); let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); // seed db with test specific data let mut txn = pool.clone().begin().await?; @@ -140,7 +142,7 @@ async fn test_service_provider_rewards_halt_on_invalid_sp(pool: PgPool) -> anyho valid_sps.insert(PAYER_1.to_string(), SP_1.to_string()); let carrier_client = MockCarrierServiceClient::new(valid_sps); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let mut txn = pool.clone().begin().await?; seed_hotspot_data_invalid_sp(reward_info.epoch_period.end, &mut txn).await?; @@ -187,7 +189,7 @@ async fn test_service_provider_promotion_rewards(pool: PgPool) -> anyhow::Result ], }]); - let reward_info = default_rewards_info(82_191_780_821_917, Duration::hours(24)); + let reward_info = default_rewards_info(EMISSIONS_POOL_IN_BONES_24_HOURS, Duration::hours(24)); let (mobile_rewards_client, mut mobile_rewards) = common::create_file_sink(); @@ -254,7 +256,7 @@ async fn test_service_provider_promotion_rewards(pool: PgPool) -> anyhow::Result - 50_999 // 85% service provider rewards rounded down - 8_998 // 15% service provider promotions - 8_998 // matched promotion - + 2; // unexpected rounding - TODO investigate + + 2; // rounding assert_eq!(unallocated.amount, expected_unallocated); From e2119e4f86ae5c3683793e7ca68d1ab77d578c48 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Wed, 18 Dec 2024 10:48:07 +0000 Subject: [PATCH 29/36] resolve subdao address via helium lib --- Cargo.lock | 1 + mobile_config/Cargo.toml | 1 + mobile_config/src/client/sub_dao_client.rs | 7 ++++--- mobile_verifier/src/cli/reward_from_db.rs | 7 +++++-- mobile_verifier/src/lib.rs | 7 +++++-- mobile_verifier/src/rewarder.rs | 15 ++++++++++----- mobile_verifier/tests/integrations/common/mod.rs | 3 ++- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cac0dc9c..c0a66f49c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5050,6 +5050,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", + "helium-lib", "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", diff --git a/mobile_config/Cargo.toml b/mobile_config/Cargo.toml index ae323e008..a6156f19e 100644 --- a/mobile_config/Cargo.toml +++ b/mobile_config/Cargo.toml @@ -22,6 +22,7 @@ file-store = { path = "../file_store" } futures = { workspace = true } futures-util = { workspace = true } helium-crypto = { workspace = true, features = ["sqlx-postgres"] } +helium-lib = { workspace = true } helium-proto = { workspace = true } humantime = { workspace = true } humantime-serde = { workspace = true } diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index 3f89ea4c3..b33bf5678 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -2,6 +2,7 @@ use super::{call_with_retry, ClientError, Settings}; use crate::sub_dao_epoch_reward_info::EpochRewardInfo; use file_store::traits::MsgVerify; use helium_crypto::{Keypair, PublicKey, Sign}; +use helium_lib::keypair::Pubkey; use helium_proto::{ services::{ sub_dao::{self, SubDaoEpochRewardInfoReqV1}, @@ -34,7 +35,7 @@ pub trait SubDaoEpochRewardInfoResolver: Clone + Send + Sync + 'static { async fn resolve_info( &self, - sub_dao: &str, + sub_dao: &Pubkey, epoch: u64, ) -> Result, Self::Error>; } @@ -45,11 +46,11 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { async fn resolve_info( &self, - sub_dao: &str, + sub_dao: &Pubkey, epoch: u64, ) -> Result, Self::Error> { let mut request = SubDaoEpochRewardInfoReqV1 { - sub_dao_address: sub_dao.into(), + sub_dao_address: sub_dao.to_string(), epoch, signer: self.signing_key.public_key().into(), signature: vec![], diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index a2891b5a9..f00fe9400 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -1,12 +1,13 @@ use crate::{ heartbeats::HeartbeatReward, + resolve_subdao_pubkey, reward_shares::{ get_scheduled_tokens_for_poc, CoverageShares, DataTransferAndPocAllocatedRewardBuckets, }, rewarder::boosted_hex_eligibility::BoostedHexEligibility, sp_boosted_rewards_bans::BannedRadios, speedtests_average::SpeedtestAverages, - unique_connections, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, + unique_connections, Settings, }; use anyhow::Result; use helium_crypto::PublicKey; @@ -32,8 +33,10 @@ impl Cmd { let reward_epoch = self.reward_epoch; let sub_dao_rewards_client = SubDaoClient::from_settings(&settings.config_client)?; + let sub_dao = resolve_subdao_pubkey(); + let reward_info = sub_dao_rewards_client - .resolve_info(MOBILE_SUB_DAO_ONCHAIN_ADDRESS, reward_epoch) + .resolve_info(&sub_dao, reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/src/lib.rs b/mobile_verifier/src/lib.rs index ce37c18b6..cd326d3a7 100644 --- a/mobile_verifier/src/lib.rs +++ b/mobile_verifier/src/lib.rs @@ -22,11 +22,10 @@ pub mod unique_connections; pub use settings::Settings; use async_trait::async_trait; +use helium_lib::keypair::Pubkey; use rust_decimal::Decimal; use std::error::Error; -pub const MOBILE_SUB_DAO_ONCHAIN_ADDRESS: &str = "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk"; - pub enum GatewayResolution { GatewayNotFound, GatewayNotAsserted, @@ -122,3 +121,7 @@ impl PriceInfo { } } } + +pub fn resolve_subdao_pubkey() -> Pubkey { + helium_lib::dao::SubDao::Mobile.key() +} diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 54c31c473..3eaf24f48 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -2,7 +2,7 @@ use crate::{ boosting_oracles::db::check_for_unprocessed_data_sets, coverage, data_session, heartbeats::{self, HeartbeatReward}, - radio_threshold, + radio_threshold, resolve_subdao_pubkey, reward_shares::{ self, CalculatedPocRewardShares, CoverageShares, DataTransferAndPocAllocatedRewardBuckets, MapperShares, TransferRewards, @@ -11,7 +11,7 @@ use crate::{ sp_boosted_rewards_bans, speedtests, speedtests_average::SpeedtestAverages, subscriber_location, subscriber_verified_mapping_event, telemetry, unique_connections, - PriceInfo, Settings, MOBILE_SUB_DAO_ONCHAIN_ADDRESS, + PriceInfo, Settings, }; use anyhow::bail; use chrono::{DateTime, TimeZone, Utc}; @@ -24,6 +24,7 @@ use file_store::{ use futures_util::TryFutureExt; use self::boosted_hex_eligibility::BoostedHexEligibility; +use helium_lib::keypair::Pubkey; use helium_lib::token::Token; use helium_proto::{ reward_manifest::RewardData::MobileRewardData, @@ -58,7 +59,7 @@ mod db; const REWARDS_NOT_CURRENT_DELAY_PERIOD: i64 = 5; pub struct Rewarder { - sub_dao_address: String, + sub_dao: Pubkey, pool: Pool, carrier_client: A, hex_service_client: B, @@ -140,8 +141,12 @@ where price_tracker: PriceTracker, speedtest_averages: FileSinkClient, ) -> anyhow::Result { + // get the subdao address + let sub_dao = resolve_subdao_pubkey(); + tracing::info!("Mobile SubDao pubkey: {}", sub_dao); + Ok(Self { - sub_dao_address: MOBILE_SUB_DAO_ONCHAIN_ADDRESS.into(), + sub_dao, pool, carrier_client, hex_service_client, @@ -246,7 +251,7 @@ where pub async fn reward(&self, next_reward_epoch: u64) -> anyhow::Result<()> { let reward_info = self .sub_dao_epoch_reward_client - .resolve_info(&self.sub_dao_address, next_reward_epoch) + .resolve_info(&self.sub_dao, next_reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index aaeea9e60..32aec3fdf 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -5,6 +5,7 @@ use file_store::{ }; use futures::{stream, StreamExt}; use helium_crypto::PublicKeyBinary; +use helium_lib::keypair::Pubkey; use helium_lib::token::Token; use helium_proto::services::{ mobile_config::NetworkKeyRole, @@ -79,7 +80,7 @@ impl SubDaoEpochRewardInfoResolver for MockSubDaoRewardsClient { async fn resolve_info( &self, - _sub_dao: &str, + _sub_dao: &Pubkey, _epoch: u64, ) -> Result, Self::Error> { Ok(self.info.clone()) From edb0d5fd148e8199148115d2fdc52f036870cb87 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Wed, 18 Dec 2024 11:54:02 +0000 Subject: [PATCH 30/36] bump deps --- Cargo.lock | 10 +++++----- mobile_verifier/src/reward_shares.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0a66f49c..6a076d120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#57e59d25ca7ae2e7ae84174842aaa50fbdd5ca74" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#572b06ee958160d7055a77d958abc18dc5a1d660" dependencies = [ "base64 0.21.7", "byteorder", @@ -1625,7 +1625,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", ] @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#57e59d25ca7ae2e7ae84174842aaa50fbdd5ca74" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#572b06ee958160d7055a77d958abc18dc5a1d660" dependencies = [ "bytes", "prost", @@ -3837,7 +3837,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#16d6838b88a35ac88797d0c7eb14a932b214a856" +source = "git+https://github.com/helium/proto?branch=master#b4c8c8f47dfff38a2ff1b7fe14e1b2a1beea651c" dependencies = [ "bytes", "prost", @@ -10008,7 +10008,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", "twox-hash", "xorf", diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index e23a19bda..131fb1489 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -11,7 +11,7 @@ use crate::{ unique_connections::{self, UniqueConnectionCounts}, PriceInfo, }; -use chrono::{DateTime, Duration, Utc}; +use chrono::{DateTime, Utc}; use coverage_point_calculator::{ BytesPs, LocationTrust, OracleBoostingStatus, RadioType, SPBoostedRewardEligibility, Speedtest, SpeedtestTier, From 343bae1d0125a34a64e6ad84f01f95b7989e4af4 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 20 Dec 2024 14:36:10 +0000 Subject: [PATCH 31/36] bump helium lib --- Cargo.lock | 54 +++++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a076d120..15c7b435b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,8 +356,7 @@ dependencies = [ [[package]] name = "anchor-gen" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3b9def91d1f0c23b99be210afea0990f931a1edae439ea30e0da50baeaea8f" +source = "git+https://github.com/ChewingGlass/anchor-gen.git?branch=master#e6136a50918660c8bab0101568068419cbd23420" dependencies = [ "anchor-generate-cpi-crate", "anchor-generate-cpi-interface", @@ -366,8 +365,7 @@ dependencies = [ [[package]] name = "anchor-generate-cpi-crate" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e8733d55b8492bde0d6f219c25769786758ff9e5e90a16e6a348f91284af50" +source = "git+https://github.com/ChewingGlass/anchor-gen.git?branch=master#e6136a50918660c8bab0101568068419cbd23420" dependencies = [ "anchor-idl", "syn 1.0.109", @@ -376,8 +374,7 @@ dependencies = [ [[package]] name = "anchor-generate-cpi-interface" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7092a50cf959ebf53460162cb07e88d4cc8ea7fa8c45292e80503a3186033daf" +source = "git+https://github.com/ChewingGlass/anchor-gen.git?branch=master#e6136a50918660c8bab0101568068419cbd23420" dependencies = [ "anchor-idl", "darling 0.14.2", @@ -387,8 +384,7 @@ dependencies = [ [[package]] name = "anchor-idl" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de2665dc06ee0bd3c7d08f47f136a3d5b1e34b7ac1bc632c86a812add04d68b" +source = "git+https://github.com/ChewingGlass/anchor-gen.git?branch=master#e6136a50918660c8bab0101568068419cbd23420" dependencies = [ "anchor-syn 0.24.2", "darling 0.14.2", @@ -1625,7 +1621,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", ] @@ -2129,7 +2125,7 @@ dependencies = [ [[package]] name = "circuit-breaker" version = "0.1.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -2771,7 +2767,7 @@ dependencies = [ [[package]] name = "data-credits" version = "0.2.2" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -3149,7 +3145,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fanout" version = "0.1.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -3725,7 +3721,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "helium-anchor-gen" version = "0.1.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -3754,7 +3750,7 @@ dependencies = [ "bs58 0.5.0", "byteorder", "ed25519-compact", - "getrandom 0.1.16", + "getrandom 0.2.10", "k256", "lazy_static", "multihash", @@ -3772,7 +3768,7 @@ dependencies = [ [[package]] name = "helium-entity-manager" version = "0.2.11" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -3781,7 +3777,7 @@ dependencies = [ [[package]] name = "helium-lib" version = "0.0.0" -source = "git+https://github.com/helium/helium-wallet-rs.git?branch=master#6b8a6bbf343027087a401cd907c9f6c848991aac" +source = "git+https://github.com/helium/helium-wallet-rs.git?branch=master#21208fcf8dcaaee955fa38798d9fa0da6b8d3f7b" dependencies = [ "anchor-client", "anchor-spl", @@ -3796,7 +3792,6 @@ dependencies = [ "helium-crypto", "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", "hex", - "hex-literal", "itertools", "jsonrpc_client", "lazy_static", @@ -3812,6 +3807,7 @@ dependencies = [ "solana-transaction-status", "spl-account-compression", "spl-associated-token-account 3.0.2", + "spl-memo", "thiserror", "tonic", "tracing", @@ -3853,7 +3849,7 @@ dependencies = [ [[package]] name = "helium-sub-daos" version = "0.1.8" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -3907,7 +3903,7 @@ checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "hexboosting" version = "0.1.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -4719,7 +4715,7 @@ dependencies = [ [[package]] name = "lazy-distributor" version = "0.2.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -4728,7 +4724,7 @@ dependencies = [ [[package]] name = "lazy-transactions" version = "0.2.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -5109,7 +5105,7 @@ dependencies = [ [[package]] name = "mobile-entity-manager" version = "0.1.3" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -5543,7 +5539,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 2.0.58", @@ -5966,7 +5962,7 @@ dependencies = [ [[package]] name = "price-oracle" version = "0.2.1" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -6615,7 +6611,7 @@ dependencies = [ [[package]] name = "rewards-oracle" version = "0.2.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -9292,7 +9288,7 @@ dependencies = [ [[package]] name = "treasury-management" version = "0.2.0" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -9338,7 +9334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] @@ -9540,7 +9536,7 @@ dependencies = [ [[package]] name = "voter-stake-registry" version = "0.3.3" -source = "git+https://github.com/helium/helium-anchor-gen.git#a7e694d49245ca9830bcfef68cce34f230c91011" +source = "git+https://github.com/helium/helium-anchor-gen.git#3036b33793cfe54b20ab24761677493510d5bd50" dependencies = [ "anchor-gen", "anchor-lang 0.29.0", @@ -10008,7 +10004,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", "twox-hash", "xorf", From a7fa7b2f0bf8d015fd3ba243a6826bea564be7c9 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Fri, 20 Dec 2024 15:43:51 +0000 Subject: [PATCH 32/36] testing without helium lib as a dep of mobile config --- Cargo.lock | 1 - mobile_config/Cargo.toml | 1 - mobile_config/src/client/sub_dao_client.rs | 5 ++--- mobile_verifier/src/cli/reward_from_db.rs | 2 +- mobile_verifier/src/rewarder.rs | 2 +- mobile_verifier/tests/integrations/common/mod.rs | 3 +-- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15c7b435b..3afb82266 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5046,7 +5046,6 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-lib", "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", diff --git a/mobile_config/Cargo.toml b/mobile_config/Cargo.toml index a6156f19e..ae323e008 100644 --- a/mobile_config/Cargo.toml +++ b/mobile_config/Cargo.toml @@ -22,7 +22,6 @@ file-store = { path = "../file_store" } futures = { workspace = true } futures-util = { workspace = true } helium-crypto = { workspace = true, features = ["sqlx-postgres"] } -helium-lib = { workspace = true } helium-proto = { workspace = true } humantime = { workspace = true } humantime-serde = { workspace = true } diff --git a/mobile_config/src/client/sub_dao_client.rs b/mobile_config/src/client/sub_dao_client.rs index b33bf5678..adcba54ac 100644 --- a/mobile_config/src/client/sub_dao_client.rs +++ b/mobile_config/src/client/sub_dao_client.rs @@ -2,7 +2,6 @@ use super::{call_with_retry, ClientError, Settings}; use crate::sub_dao_epoch_reward_info::EpochRewardInfo; use file_store::traits::MsgVerify; use helium_crypto::{Keypair, PublicKey, Sign}; -use helium_lib::keypair::Pubkey; use helium_proto::{ services::{ sub_dao::{self, SubDaoEpochRewardInfoReqV1}, @@ -35,7 +34,7 @@ pub trait SubDaoEpochRewardInfoResolver: Clone + Send + Sync + 'static { async fn resolve_info( &self, - sub_dao: &Pubkey, + sub_dao: &str, epoch: u64, ) -> Result, Self::Error>; } @@ -46,7 +45,7 @@ impl SubDaoEpochRewardInfoResolver for SubDaoClient { async fn resolve_info( &self, - sub_dao: &Pubkey, + sub_dao: &str, epoch: u64, ) -> Result, Self::Error> { let mut request = SubDaoEpochRewardInfoReqV1 { diff --git a/mobile_verifier/src/cli/reward_from_db.rs b/mobile_verifier/src/cli/reward_from_db.rs index f00fe9400..779e8c8e8 100644 --- a/mobile_verifier/src/cli/reward_from_db.rs +++ b/mobile_verifier/src/cli/reward_from_db.rs @@ -36,7 +36,7 @@ impl Cmd { let sub_dao = resolve_subdao_pubkey(); let reward_info = sub_dao_rewards_client - .resolve_info(&sub_dao, reward_epoch) + .resolve_info(&sub_dao.to_string(), reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 3eaf24f48..6f264b636 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -251,7 +251,7 @@ where pub async fn reward(&self, next_reward_epoch: u64) -> anyhow::Result<()> { let reward_info = self .sub_dao_epoch_reward_client - .resolve_info(&self.sub_dao, next_reward_epoch) + .resolve_info(&self.sub_dao.to_string(), next_reward_epoch) .await? .ok_or(anyhow::anyhow!( "No reward info found for epoch {}", diff --git a/mobile_verifier/tests/integrations/common/mod.rs b/mobile_verifier/tests/integrations/common/mod.rs index 32aec3fdf..aaeea9e60 100644 --- a/mobile_verifier/tests/integrations/common/mod.rs +++ b/mobile_verifier/tests/integrations/common/mod.rs @@ -5,7 +5,6 @@ use file_store::{ }; use futures::{stream, StreamExt}; use helium_crypto::PublicKeyBinary; -use helium_lib::keypair::Pubkey; use helium_lib::token::Token; use helium_proto::services::{ mobile_config::NetworkKeyRole, @@ -80,7 +79,7 @@ impl SubDaoEpochRewardInfoResolver for MockSubDaoRewardsClient { async fn resolve_info( &self, - _sub_dao: &Pubkey, + _sub_dao: &str, _epoch: u64, ) -> Result, Self::Error> { Ok(self.info.clone()) From 1646c90ad396b2559f3368ad5f421278cbb35914 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 6 Jan 2025 13:35:59 +0000 Subject: [PATCH 33/36] bump deps --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3afb82266..11a28221b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1611,7 +1611,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#572b06ee958160d7055a77d958abc18dc5a1d660" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#d63af39f95c55e589dcf5fe028f9b958e691f6a4" dependencies = [ "base64 0.21.7", "byteorder", @@ -1621,7 +1621,7 @@ dependencies = [ "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", ] @@ -3750,7 +3750,7 @@ dependencies = [ "bs58 0.5.0", "byteorder", "ed25519-compact", - "getrandom 0.2.10", + "getrandom 0.1.16", "k256", "lazy_static", "multihash", @@ -3817,7 +3817,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#572b06ee958160d7055a77d958abc18dc5a1d660" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#d63af39f95c55e589dcf5fe028f9b958e691f6a4" dependencies = [ "bytes", "prost", @@ -3833,7 +3833,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#b4c8c8f47dfff38a2ff1b7fe14e1b2a1beea651c" +source = "git+https://github.com/helium/proto?branch=master#4085e00c6f4d82c3da798ae1bc97324bc9cada2e" dependencies = [ "bytes", "prost", @@ -5538,7 +5538,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn 2.0.58", @@ -6078,7 +6078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.5.0", + "heck 0.4.0", "itertools", "log", "multimap", @@ -9333,7 +9333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] @@ -10003,7 +10003,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.9.9", "thiserror", "twox-hash", "xorf", From 004957c2a8086db9960a71cf460f05e63048e723 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 7 Jan 2025 11:35:17 +0000 Subject: [PATCH 34/36] tmp add one hours to epoch window to allign with current rewards window --- mobile_config/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mobile_config/src/lib.rs b/mobile_config/src/lib.rs index fc81cae09..4f896e186 100644 --- a/mobile_config/src/lib.rs +++ b/mobile_config/src/lib.rs @@ -105,7 +105,9 @@ pub struct EpochInfo { impl From for EpochInfo { fn from(next_reward_epoch: u64) -> Self { - let start_time = DateTime::::UNIX_EPOCH + Duration::days(next_reward_epoch as i64); + let start_time = DateTime::::UNIX_EPOCH + + Duration::days(next_reward_epoch as i64) + + Duration::hours(1); let end_time = start_time + Duration::days(1); EpochInfo { period: start_time..end_time, From 7632285fd33b452c85d47dc7cd34c87e0f261bc5 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 7 Jan 2025 11:36:27 +0000 Subject: [PATCH 35/36] accommodate hnt_rewards_issued column not being available, if hnt_rewards_issued is zero bail from rewarding --- Cargo.lock | 53 +++++++------------ Cargo.toml | 4 +- iot_verifier/src/rewarder.rs | 3 +- .../src/sub_dao_epoch_reward_info.rs | 11 ++-- mobile_verifier/src/rewarder.rs | 15 ++++-- 5 files changed, 42 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11a28221b..7fd06ed19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,7 +1615,7 @@ source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-sup dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "prost", "rand 0.8.5", "rand_chacha 0.3.0", @@ -1784,7 +1784,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -2626,7 +2626,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "notify", "serde", @@ -3208,7 +3208,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-literal", "http 0.2.11", "lazy_static", @@ -3790,7 +3790,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", + "helium-proto", "hex", "itertools", "jsonrpc_client", @@ -3817,23 +3817,6 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#d63af39f95c55e589dcf5fe028f9b958e691f6a4" -dependencies = [ - "bytes", - "prost", - "prost-build", - "serde", - "serde_json", - "strum", - "strum_macros", - "tonic", - "tonic-build", -] - -[[package]] -name = "helium-proto" -version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=master#4085e00c6f4d82c3da798ae1bc97324bc9cada2e" dependencies = [ "bytes", "prost", @@ -3887,7 +3870,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4303,7 +4286,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "humantime-serde", "metrics", @@ -4373,7 +4356,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -4415,7 +4398,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -4457,7 +4440,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http-serde", "humantime-serde", "iot-config", @@ -5046,7 +5029,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hextree", "http 0.2.11", "http-serde", @@ -5089,7 +5072,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "mobile-config", "prost", "rand 0.8.5", @@ -5125,7 +5108,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "http-serde", "humantime-serde", @@ -5170,7 +5153,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "hex-assignments", "hextree", "http-serde", @@ -5854,7 +5837,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5937,7 +5920,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6078,7 +6061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.4.0", + "heck 0.5.0", "itertools", "log", "multimap", @@ -6576,7 +6559,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", + "helium-proto", "humantime-serde", "lazy_static", "metrics", diff --git a/Cargo.toml b/Cargo.toml index acac87a64..fae3f6697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # -# [patch.'https://github.com/helium/proto'] -# helium-proto = { path = "../../proto" } + [patch.'https://github.com/helium/proto'] + helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" } diff --git a/iot_verifier/src/rewarder.rs b/iot_verifier/src/rewarder.rs index c3b886362..75e0449ff 100644 --- a/iot_verifier/src/rewarder.rs +++ b/iot_verifier/src/rewarder.rs @@ -12,7 +12,7 @@ use helium_proto::{ self as proto, iot_reward_share::Reward as ProtoReward, UnallocatedReward, UnallocatedRewardType, }, - IotRewardData as ManifestIotRewardData, RewardManifest, + IotRewardData as ManifestIotRewardData, IotRewardToken, RewardManifest, }; use humantime_serde::re::humantime; use price::PriceTracker; @@ -166,6 +166,7 @@ impl Rewarder { dc_bones_per_share: Some(helium_proto::Decimal { value: poc_dc_shares.dc_transfer_rewards_per_share.to_string(), }), + token: IotRewardToken::Hnt as i32, }; self.reward_manifests_sink .write( diff --git a/mobile_config/src/sub_dao_epoch_reward_info.rs b/mobile_config/src/sub_dao_epoch_reward_info.rs index b356c9566..184af8196 100644 --- a/mobile_config/src/sub_dao_epoch_reward_info.rs +++ b/mobile_config/src/sub_dao_epoch_reward_info.rs @@ -73,7 +73,7 @@ pub(crate) mod db { address AS epoch_address, sub_dao AS sub_dao_address, epoch::BIGINT, - hnt_rewards_issued::BIGINT, + delegation_rewards_issued::BIGINT as hnt_rewards_issued, delegation_rewards_issued::BIGINT, rewards_issued_at::BIGINT FROM sub_dao_epoch_infos @@ -103,12 +103,17 @@ pub(crate) mod db { as u64) .to_timestamp() .map_err(|err| sqlx::Error::Decode(Box::new(err)))?; - + let hnt_rewards_issued = row.get::("hnt_rewards_issued") as u64; + if hnt_rewards_issued == 0 { + return Err(sqlx::Error::Decode(Box::new(sqlx::Error::Decode( + Box::from("hnt_rewards_issued is 0"), + )))); + } Ok(Self { epoch: row.get::("epoch") as u64, epoch_address: row.get::("epoch_address"), sub_dao_address: row.get::("sub_dao_address"), - hnt_rewards_issued: row.get::("hnt_rewards_issued") as u64, + hnt_rewards_issued, delegation_rewards_issued: row.get::("delegation_rewards_issued") as u64, rewards_issued_at, }) diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 6f264b636..2be924a1d 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -33,7 +33,7 @@ use helium_proto::{ service_provider_boosted_rewards_banned_radio_req_v1::SpBoostedRewardsBannedRadioBanType, MobileRewardShare, UnallocatedReward, UnallocatedRewardType, }, - MobileRewardData as ManifestMobileRewardData, RewardManifest, + MobileRewardData as ManifestMobileRewardData, MobileRewardToken, RewardManifest, }; use mobile_config::{ boosted_hex_info::BoostedHexes, @@ -177,8 +177,16 @@ where let now = Utc::now(); let sleep_duration = if scheduler.should_trigger(now) { if self.is_data_current(&scheduler.schedule_period).await? { - self.reward(next_reward_epoch).await?; - continue; + match self.reward(next_reward_epoch).await { + Ok(_) => { + tracing::info!("Successfully rewarded for epoch {}", next_reward_epoch); + continue; + } + Err(e) => { + tracing::error!("Failed to reward: {}", e); + chrono::Duration::minutes(REWARDS_NOT_CURRENT_DELAY_PERIOD).to_std()? + } + } } else { chrono::Duration::minutes(REWARDS_NOT_CURRENT_DELAY_PERIOD).to_std()? } @@ -342,6 +350,7 @@ where value: poc_dc_shares.boost.to_string(), }), service_provider_promotions: sp_promotions.into_proto(), + token: MobileRewardToken::Hnt as i32, }; self.reward_manifests .write( From 61a35a806af7870cfd87f93bc9ccfa22d1cb8cb6 Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Tue, 7 Jan 2025 11:43:35 +0000 Subject: [PATCH 36/36] remove local proto dep --- Cargo.lock | 57 +++++++++++++++++++++++++++++++++++------------------- Cargo.toml | 4 ++-- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fd06ed19..35dc33d05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1611,17 +1611,17 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#d63af39f95c55e589dcf5fe028f9b958e691f6a4" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#f7b68c095f86afdf904f6a38db8af03af99c9a86" dependencies = [ "base64 0.21.7", "byteorder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "prost", "rand 0.8.5", "rand_chacha 0.3.0", "rust_decimal", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", ] @@ -1784,7 +1784,7 @@ dependencies = [ "file-store", "futures", "futures-util", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -2626,7 +2626,7 @@ dependencies = [ "axum 0.7.4", "bs58 0.4.0", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "notify", "serde", @@ -3208,7 +3208,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-literal", "http 0.2.11", "lazy_static", @@ -3790,7 +3790,7 @@ dependencies = [ "h3o", "helium-anchor-gen", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=master)", "hex", "itertools", "jsonrpc_client", @@ -3817,6 +3817,23 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support#f7b68c095f86afdf904f6a38db8af03af99c9a86" +dependencies = [ + "bytes", + "prost", + "prost-build", + "serde", + "serde_json", + "strum", + "strum_macros", + "tonic", + "tonic-build", +] + +[[package]] +name = "helium-proto" +version = "0.1.0" +source = "git+https://github.com/helium/proto?branch=master#4085e00c6f4d82c3da798ae1bc97324bc9cada2e" dependencies = [ "bytes", "prost", @@ -3870,7 +3887,7 @@ dependencies = [ "async-trait", "chrono", "derive_builder", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "rust_decimal", "rust_decimal_macros", @@ -4286,7 +4303,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "humantime-serde", "metrics", @@ -4356,7 +4373,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -4398,7 +4415,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -4440,7 +4457,7 @@ dependencies = [ "futures-util", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http-serde", "humantime-serde", "iot-config", @@ -5029,7 +5046,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hextree", "http 0.2.11", "http-serde", @@ -5072,7 +5089,7 @@ dependencies = [ "futures", "h3o", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "mobile-config", "prost", "rand 0.8.5", @@ -5108,7 +5125,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "http-serde", "humantime-serde", @@ -5153,7 +5170,7 @@ dependencies = [ "h3o", "helium-crypto", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "hex-assignments", "hextree", "http-serde", @@ -5837,7 +5854,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "http 0.2.11", "hyper 0.14.28", "jsonrpsee", @@ -5920,7 +5937,7 @@ dependencies = [ "futures-util", "helium-anchor-gen", "helium-lib", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "metrics", "metrics-exporter-prometheus", @@ -6559,7 +6576,7 @@ dependencies = [ "futures", "futures-util", "helium-crypto", - "helium-proto", + "helium-proto 0.1.0 (git+https://github.com/helium/proto?branch=andymck%2Fsub-dao-epoch-support)", "humantime-serde", "lazy_static", "metrics", @@ -9986,7 +10003,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "thiserror", "twox-hash", "xorf", diff --git a/Cargo.toml b/Cargo.toml index fae3f6697..acac87a64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,6 @@ sqlx = { git = "https://github.com/launchbadge/sqlx.git", rev = "42dd78fe931df65 # Patching for beacon must point directly to the crate, it will not look in the # repo for sibling crates. # - [patch.'https://github.com/helium/proto'] - helium-proto = { path = "../../proto" } +# [patch.'https://github.com/helium/proto'] +# helium-proto = { path = "../../proto" } # beacon = { path = "../../proto" }