diff --git a/Cargo.lock b/Cargo.lock index aff72018e..1939a2f4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1130,7 +1130,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/service-provider-rewards#b15424e33a8e9302e6557108cad8c4ee90a3dc6e" +source = "git+https://github.com/helium/proto?branch=andymck/service-provider-rewards#f619e43167519efa3be5571a6c6a3b7941b9d9f2" dependencies = [ "base64 0.21.0", "byteorder", @@ -3003,7 +3003,7 @@ dependencies = [ [[package]] name = "helium-proto" version = "0.1.0" -source = "git+https://github.com/helium/proto?branch=andymck/service-provider-rewards#b15424e33a8e9302e6557108cad8c4ee90a3dc6e" +source = "git+https://github.com/helium/proto?branch=andymck/service-provider-rewards#f619e43167519efa3be5571a6c6a3b7941b9d9f2" dependencies = [ "bytes", "prost", diff --git a/file_store/src/cli/dump.rs b/file_store/src/cli/dump.rs index b2cffceed..553bb4d92 100644 --- a/file_store/src/cli/dump.rs +++ b/file_store/src/cli/dump.rs @@ -230,6 +230,10 @@ impl Cmd { "service_provider": reward.service_provider_id, "amount": reward.amount, }))?, + Some(Reward::UnallocatedReward(reward)) => print_json(&json!({ + "unallocated_reward_type": reward.reward_type, + "amount": reward.amount, + }))?, _ => (), } } diff --git a/mobile_verifier/src/reward_shares.rs b/mobile_verifier/src/reward_shares.rs index c1088721d..559f2d7e9 100644 --- a/mobile_verifier/src/reward_shares.rs +++ b/mobile_verifier/src/reward_shares.rs @@ -10,6 +10,7 @@ use futures::{Stream, StreamExt}; use helium_crypto::PublicKeyBinary; use helium_proto::services::{ poc_mobile as proto, poc_mobile::mobile_reward_share::Reward as ProtoReward, + poc_mobile::UnallocatedReward, poc_mobile::UnallocatedRewardType, }; use mobile_config::client::carrier_service_client::CarrierServiceVerifier; use mobile_config::client::ClientError; @@ -262,7 +263,7 @@ impl ServiceProviderShares { self, reward_period: &'_ Range>, reward_per_share: Decimal, - ) -> impl Iterator + '_ { + ) -> impl Iterator + '_ { self.shares .into_iter() .map(move |share| proto::ServiceProviderReward { @@ -273,13 +274,36 @@ impl ServiceProviderShares { .unwrap_or(0), }) .filter(|service_provider_reward| service_provider_reward.amount > 0) - .map(|service_provider_reward| proto::MobileRewardShare { - start_period: reward_period.start.encode_timestamp(), - end_period: reward_period.end.encode_timestamp(), - reward: Some(ProtoReward::ServiceProviderReward(service_provider_reward)), + .map(|service_provider_reward| { + ( + service_provider_reward.amount, + proto::MobileRewardShare { + start_period: reward_period.start.encode_timestamp(), + end_period: reward_period.end.encode_timestamp(), + reward: Some(ProtoReward::ServiceProviderReward(service_provider_reward)), + }, + ) }) } + pub fn unallocated_reward( + unallocated_amount: Decimal, + reward_period: &'_ Range>, + ) -> anyhow::Result { + let reward = UnallocatedReward { + reward_type: UnallocatedRewardType::ServiceProvider as i32, + amount: unallocated_amount + .round_dp_with_strategy(0, RoundingStrategy::ToZero) + .to_u64() + .unwrap_or(0), + }; + Ok(proto::MobileRewardShare { + start_period: reward_period.start.encode_timestamp(), + end_period: reward_period.end.encode_timestamp(), + reward: Some(ProtoReward::UnallocatedReward(reward)), + }) + } + fn normalize_service_provider_rewards( total_sp_rewards_used: Decimal, total_sp_rewards: Decimal, @@ -550,7 +574,9 @@ mod test { .unwrap(); let mut sp_rewards = HashMap::new(); - for sp_reward in sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) { + for (_amount, sp_reward) in + sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) + { if let Some(MobileReward::ServiceProviderReward(r)) = sp_reward.reward { sp_rewards.insert(r.service_provider_id, r.amount); } @@ -597,7 +623,9 @@ mod test { .unwrap(); let mut sp_rewards = HashMap::new(); - for sp_reward in sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) { + for (_amount, sp_reward) in + sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) + { if let Some(MobileReward::ServiceProviderReward(r)) = sp_reward.reward { sp_rewards.insert(r.service_provider_id, r.amount); } @@ -637,7 +665,9 @@ mod test { .unwrap(); let mut sp_rewards = HashMap::new(); - for sp_reward in sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) { + for (_amount, sp_reward) in + sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) + { if let Some(MobileReward::ServiceProviderReward(r)) = sp_reward.reward { sp_rewards.insert(r.service_provider_id, r.amount); } @@ -669,7 +699,9 @@ mod test { .unwrap(); let mut sp_rewards = HashMap::new(); - for sp_reward in sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) { + for (_amount, sp_reward) in + sp_shares.into_service_provider_rewards(&epoch, rewards_per_share) + { if let Some(MobileReward::ServiceProviderReward(r)) = sp_reward.reward { sp_rewards.insert(r.service_provider_id, r.amount); } diff --git a/mobile_verifier/src/rewarder.rs b/mobile_verifier/src/rewarder.rs index 835827a4e..a4dec38af 100644 --- a/mobile_verifier/src/rewarder.rs +++ b/mobile_verifier/src/rewarder.rs @@ -10,6 +10,7 @@ use anyhow::bail; use chrono::{DateTime, Duration, TimeZone, Utc}; use db_store::meta; use file_store::{file_sink::FileSinkClient, traits::TimestampEncode}; + use helium_proto::RewardManifest; use mobile_config::client::{carrier_service_client::CarrierServiceVerifier, ClientError}; use price::PriceTracker; @@ -229,13 +230,28 @@ where .get_scheduled_tokens_for_service_providers(reward_period.end - reward_period.start); let rewards_per_share = sp_shares.rewards_per_share(total_sp_rewards, mobile_bone_price)?; // translate service provider shares into service provider rewards - for sp_share in sp_shares.into_service_provider_rewards(reward_period, rewards_per_share) { + // track the amount of allocated reward value as we go + let mut allocated_sp_rewards = 0_u64; + for (amount, sp_share) in + sp_shares.into_service_provider_rewards(reward_period, rewards_per_share) + { + allocated_sp_rewards += amount; self.mobile_rewards .write(sp_share.clone(), []) .await? // Await the returned one shot to ensure that we wrote the file .await??; } + + // write out any unallocated service provider reward + let unallocated_sp_reward_amount = total_sp_rewards - Decimal::from(allocated_sp_rewards); + let unallocated_sp_reward = + ServiceProviderShares::unallocated_reward(unallocated_sp_reward_amount, reward_period)?; + self.mobile_rewards + .write(unallocated_sp_reward, []) + .await? + .await??; + let written_files = self.mobile_rewards.commit().await?.await??; let mut transaction = self.pool.begin().await?;