diff --git a/pallets/ddc-clusters/src/cluster.rs b/pallets/ddc-clusters/src/cluster.rs index 4be19d73f..ff55e49bf 100644 --- a/pallets/ddc-clusters/src/cluster.rs +++ b/pallets/ddc-clusters/src/cluster.rs @@ -3,7 +3,7 @@ use codec::{Decode, Encode}; use ddc_primitives::ClusterId; use frame_support::{pallet_prelude::*, parameter_types}; use scale_info::TypeInfo; -use sp_runtime::Perbill; +use sp_runtime::Perquintill; parameter_types! { pub MaxClusterParamsLen: u16 = 2048; @@ -32,9 +32,9 @@ pub struct ClusterParams { #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] #[scale_info(skip_type_params(Balance, BlockNumber, T))] pub struct ClusterGovParams { - pub treasury_share: Perbill, - pub validators_share: Perbill, - pub cluster_reserve_share: Perbill, + pub treasury_share: Perquintill, + pub validators_share: Perquintill, + pub cluster_reserve_share: Perquintill, pub cdn_bond_size: Balance, pub cdn_chill_delay: BlockNumber, pub cdn_unbonding_delay: BlockNumber, diff --git a/pallets/ddc-clusters/src/tests.rs b/pallets/ddc-clusters/src/tests.rs index 922ad7a7a..9e87b2e49 100644 --- a/pallets/ddc-clusters/src/tests.rs +++ b/pallets/ddc-clusters/src/tests.rs @@ -6,7 +6,7 @@ use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use frame_system::Config; use hex_literal::hex; use pallet_ddc_nodes::{CDNNodeParams, NodeParams}; -use sp_runtime::{traits::Hash, AccountId32, Perbill}; +use sp_runtime::{traits::Hash, AccountId32, Perquintill}; #[test] fn create_cluster_works() { @@ -14,9 +14,9 @@ fn create_cluster_works() { System::set_block_number(1); let cluster_gov_params = ClusterGovParams { - treasury_share: Perbill::from_float(0.05), - validators_share: Perbill::from_float(0.01), - cluster_reserve_share: Perbill::from_float(0.02), + treasury_share: Perquintill::from_float(0.05), + validators_share: Perquintill::from_float(0.01), + cluster_reserve_share: Perquintill::from_float(0.02), cdn_bond_size: 100, cdn_chill_delay: 50, cdn_unbonding_delay: 50, @@ -98,9 +98,9 @@ fn add_and_delete_node_works() { AccountId::from([2; 32]), ClusterParams { node_provider_auth_contract: AccountId::from([1; 32]) }, ClusterGovParams { - treasury_share: Perbill::from_float(0.05), - validators_share: Perbill::from_float(0.01), - cluster_reserve_share: Perbill::from_float(0.02), + treasury_share: Perquintill::from_float(0.05), + validators_share: Perquintill::from_float(0.01), + cluster_reserve_share: Perquintill::from_float(0.02), cdn_bond_size: 100, cdn_chill_delay: 50, cdn_unbonding_delay: 50, @@ -309,9 +309,9 @@ fn set_cluster_params_works() { AccountId::from([2; 32]), ClusterParams { node_provider_auth_contract: AccountId::from([1; 32]) }, ClusterGovParams { - treasury_share: Perbill::from_float(0.05), - validators_share: Perbill::from_float(0.01), - cluster_reserve_share: Perbill::from_float(0.02), + treasury_share: Perquintill::from_float(0.05), + validators_share: Perquintill::from_float(0.01), + cluster_reserve_share: Perquintill::from_float(0.02), cdn_bond_size: 100, cdn_chill_delay: 50, cdn_unbonding_delay: 50, @@ -354,9 +354,9 @@ fn set_cluster_gov_params_works() { System::set_block_number(1); let cluster_gov_params = ClusterGovParams { - treasury_share: Perbill::from_float(0.05), - validators_share: Perbill::from_float(0.01), - cluster_reserve_share: Perbill::from_float(0.02), + treasury_share: Perquintill::from_float(0.05), + validators_share: Perquintill::from_float(0.01), + cluster_reserve_share: Perquintill::from_float(0.02), cdn_bond_size: 100, cdn_chill_delay: 50, cdn_unbonding_delay: 50, diff --git a/pallets/ddc-customers/src/mock.rs b/pallets/ddc-customers/src/mock.rs index 5912347eb..43db67e76 100644 --- a/pallets/ddc-customers/src/mock.rs +++ b/pallets/ddc-customers/src/mock.rs @@ -15,7 +15,7 @@ use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - Perbill, + Perquintill, }; /// The AccountId alias in this test module. @@ -143,9 +143,9 @@ impl ClusterVisitor for TestClusterVisitor { fn get_fees_params(_cluster_id: &ClusterId) -> Result { Ok(ClusterFeesParams { - treasury_share: Perbill::from_percent(1), - validators_share: Perbill::from_percent(10), - cluster_reserve_share: Perbill::from_percent(2), + treasury_share: Perquintill::from_percent(1), + validators_share: Perquintill::from_percent(10), + cluster_reserve_share: Perquintill::from_percent(2), }) } diff --git a/pallets/ddc-payouts/src/lib.rs b/pallets/ddc-payouts/src/lib.rs index 02eba8dce..d17052f6c 100644 --- a/pallets/ddc-payouts/src/lib.rs +++ b/pallets/ddc-payouts/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; pub use pallet::*; -use sp_runtime::{PerThing, Perbill}; +use sp_runtime::{PerThing, Perquintill}; use sp_std::prelude::*; type BatchIndex = u16; @@ -89,6 +89,7 @@ pub type BalanceOf = parameter_types! { pub MaxBatchesCount: u16 = 1000; + pub MaxDust: u16 = 20000; } #[frame_support::pallet] @@ -427,8 +428,10 @@ pub mod pallet { if amount_actually_charged > 0 { // something was charged and should be added // calculate ratio - let ratio = - Perbill::from_rational(amount_actually_charged, total_customer_charge); + let ratio = Perquintill::from_rational( + amount_actually_charged, + total_customer_charge, + ); customer_charge.storage = ratio * customer_charge.storage; customer_charge.transfer = ratio * customer_charge.transfer; @@ -654,19 +657,21 @@ pub mod pallet { .ok_or(Error::::ArithmeticOverflow)?; let node_provider_id = payee.0; - let reward: BalanceOf = amount_to_reward.saturated_into::>(); - - ::Currency::transfer( - &updated_billing_report.vault, - &node_provider_id, - reward, - ExistenceRequirement::AllowDeath, - )?; - - updated_billing_report - .total_distributed_reward - .checked_add(amount_to_reward) - .ok_or(Error::::ArithmeticOverflow)?; + if amount_to_reward > 0 { + let reward: BalanceOf = amount_to_reward.saturated_into::>(); + + ::Currency::transfer( + &updated_billing_report.vault, + &node_provider_id, + reward, + ExistenceRequirement::AllowDeath, + )?; + + updated_billing_report.total_distributed_reward = updated_billing_report + .total_distributed_reward + .checked_add(amount_to_reward) + .ok_or(Error::::ArithmeticOverflow)?; + } Self::deposit_event(Event::::Rewarded { cluster_id, @@ -708,6 +713,22 @@ pub mod pallet { &billing_report.rewarding_max_batch_index, )?; + let expected_amount_to_reward = (|| -> Option { + billing_report + .total_customer_charge + .transfer + .checked_add(billing_report.total_customer_charge.storage)? + .checked_add(billing_report.total_customer_charge.puts)? + .checked_add(billing_report.total_customer_charge.gets) + })() + .ok_or(Error::::ArithmeticOverflow)?; + + ensure!( + expected_amount_to_reward - billing_report.total_distributed_reward <= + MaxDust::get().into(), + Error::::NotDistributedBalance + ); + billing_report.state = State::ProvidersRewarded; ActiveBillingReports::::insert(cluster_id, era, billing_report); @@ -729,20 +750,6 @@ pub mod pallet { .map_err(|_| Error::::BillingReportDoesNotExist)?; ensure!(billing_report.state == State::ProvidersRewarded, Error::::NotExpectedState); - let expected_amount_to_reward = (|| -> Option { - billing_report - .total_customer_charge - .transfer - .checked_add(billing_report.total_customer_charge.storage)? - .checked_add(billing_report.total_customer_charge.puts)? - .checked_add(billing_report.total_customer_charge.gets) - })() - .ok_or(Error::::ArithmeticOverflow)?; - - ensure!( - expected_amount_to_reward == billing_report.total_distributed_reward, - Error::::NotDistributedBalance - ); billing_report.charging_processed_batches.clear(); billing_report.rewarding_processed_batches.clear(); @@ -811,20 +818,23 @@ pub mod pallet { ) -> Option { let mut node_reward = NodeReward::default(); - let mut ratio = Perbill::from_rational( + let mut ratio = Perquintill::from_rational( node_usage.transferred_bytes, total_nodes_usage.transferred_bytes, ); + // ratio multiplied by X will be > 0, < X no overflow node_reward.transfer = ratio * total_customer_charge.transfer; - ratio = Perbill::from_rational(node_usage.stored_bytes, total_nodes_usage.stored_bytes); + ratio = Perquintill::from_rational(node_usage.stored_bytes, total_nodes_usage.stored_bytes); node_reward.storage = ratio * total_customer_charge.storage; - ratio = Perbill::from_rational(node_usage.number_of_puts, total_nodes_usage.number_of_puts); + ratio = + Perquintill::from_rational(node_usage.number_of_puts, total_nodes_usage.number_of_puts); node_reward.puts = ratio * total_customer_charge.puts; - ratio = Perbill::from_rational(node_usage.number_of_gets, total_nodes_usage.number_of_gets); + ratio = + Perquintill::from_rational(node_usage.number_of_gets, total_nodes_usage.number_of_gets); node_reward.gets = ratio * total_customer_charge.gets; Some(node_reward) diff --git a/pallets/ddc-payouts/src/mock.rs b/pallets/ddc-payouts/src/mock.rs index 86d2581dc..74abd95f2 100644 --- a/pallets/ddc-payouts/src/mock.rs +++ b/pallets/ddc-payouts/src/mock.rs @@ -23,7 +23,7 @@ use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - DispatchError, + DispatchError, Perquintill, }; use sp_std::prelude::*; @@ -163,15 +163,15 @@ pub const PRICING_PARAMS_ONE: ClusterPricingParams = ClusterPricingParams { }; pub const PRICING_FEES: ClusterFeesParams = ClusterFeesParams { - treasury_share: Perbill::from_percent(1), - validators_share: Perbill::from_percent(10), - cluster_reserve_share: Perbill::from_percent(2), + treasury_share: Perquintill::from_percent(1), + validators_share: Perquintill::from_percent(10), + cluster_reserve_share: Perquintill::from_percent(2), }; pub const PRICING_FEES_ZERO: ClusterFeesParams = ClusterFeesParams { - treasury_share: Perbill::from_percent(0), - validators_share: Perbill::from_percent(0), - cluster_reserve_share: Perbill::from_percent(0), + treasury_share: Perquintill::from_percent(0), + validators_share: Perquintill::from_percent(0), + cluster_reserve_share: Perquintill::from_percent(0), }; pub struct TestTreasuryVisitor; diff --git a/pallets/ddc-payouts/src/tests.rs b/pallets/ddc-payouts/src/tests.rs index 4565920db..6bab56cce 100644 --- a/pallets/ddc-payouts/src/tests.rs +++ b/pallets/ddc-payouts/src/tests.rs @@ -3,7 +3,7 @@ use super::{mock::*, *}; use ddc_primitives::ClusterId; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; - +use sp_runtime::Perquintill; #[test] fn set_authorised_caller_works() { ExtBuilder.build_and_execute(|| { @@ -444,8 +444,7 @@ fn send_charging_customers_batch_works1() { let user1_debt = DdcPayouts::debtor_customers(cluster_id, user1); assert_eq!(user1_debt, None); - let balance_before = - Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); + let balance_before = Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); // batch 3 batch_index += 1; @@ -460,7 +459,7 @@ fn send_charging_customers_batch_works1() { let user3_charge = calculate_charge(cluster_id, usage3.clone()); let charge3 = calculate_charge_parts(cluster_id, usage3); - let ratio = Perbill::from_rational(PARTIAL_CHARGE, user3_charge); + let ratio = Perquintill::from_rational(PARTIAL_CHARGE, user3_charge); report = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); assert_eq!( ratio * charge3.puts + before_total_customer_charge.puts, @@ -845,11 +844,11 @@ fn end_charging_customers_works_zero_fees() { (fees.treasury_share + fees.validators_share + fees.cluster_reserve_share) .left_from_one(); - assert_eq!(total_left_from_one, Perbill::one()); + assert_eq!(total_left_from_one, Perquintill::one()); - assert_eq!(fees.treasury_share, Perbill::zero()); - assert_eq!(fees.validators_share, Perbill::zero()); - assert_eq!(fees.cluster_reserve_share, Perbill::zero()); + assert_eq!(fees.treasury_share, Perquintill::zero()); + assert_eq!(fees.validators_share, Perquintill::zero()); + assert_eq!(fees.cluster_reserve_share, Perquintill::zero()); balance = Balances::free_balance(TREASURY_ACCOUNT_ID); assert_eq!(balance, 0); @@ -1347,46 +1346,59 @@ fn send_rewarding_providers_batch_works() { payees1, )); - let mut ratio = Perbill::from_rational( + let ratio1_transfer = Perquintill::from_rational( node_usage1.transferred_bytes, total_nodes_usage.transferred_bytes, ); - let mut transfer_charge = ratio * report_after.total_customer_charge.transfer; + let mut transfer_charge = ratio1_transfer * report_after.total_customer_charge.transfer; - ratio = Perbill::from_rational(node_usage1.stored_bytes, total_nodes_usage.stored_bytes); - let mut storage_charge = ratio * report_after.total_customer_charge.storage; + let ratio1_storage = + Perquintill::from_rational(node_usage1.stored_bytes, total_nodes_usage.stored_bytes); + let mut storage_charge = ratio1_storage * report_after.total_customer_charge.storage; - ratio = - Perbill::from_rational(node_usage1.number_of_puts, total_nodes_usage.number_of_puts); - let mut puts_charge = ratio * report_after.total_customer_charge.puts; + let ratio1_puts = Perquintill::from_rational( + node_usage1.number_of_puts, + total_nodes_usage.number_of_puts, + ); + let mut puts_charge = ratio1_puts * report_after.total_customer_charge.puts; - ratio = - Perbill::from_rational(node_usage1.number_of_gets, total_nodes_usage.number_of_gets); - let mut gets_charge = ratio * report_after.total_customer_charge.gets; + let ratio1_gets = Perquintill::from_rational( + node_usage1.number_of_gets, + total_nodes_usage.number_of_gets, + ); + let mut gets_charge = ratio1_gets * report_after.total_customer_charge.gets; - let mut balance = Balances::free_balance(node1); - assert_eq!(balance, transfer_charge + storage_charge + puts_charge + gets_charge); + let balance_node1 = Balances::free_balance(node1); + assert_eq!(balance_node1, transfer_charge + storage_charge + puts_charge + gets_charge); + let mut report_reward = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - ratio = Perbill::from_rational( + let ratio2_transfer = Perquintill::from_rational( node_usage2.transferred_bytes, total_nodes_usage.transferred_bytes, ); - transfer_charge = ratio * report_after.total_customer_charge.transfer; + transfer_charge = ratio2_transfer * report_after.total_customer_charge.transfer; - ratio = Perbill::from_rational(node_usage2.stored_bytes, total_nodes_usage.stored_bytes); - storage_charge = ratio * report_after.total_customer_charge.storage; + let ratio2_storage = + Perquintill::from_rational(node_usage2.stored_bytes, total_nodes_usage.stored_bytes); + storage_charge = ratio2_storage * report_after.total_customer_charge.storage; - ratio = - Perbill::from_rational(node_usage2.number_of_puts, total_nodes_usage.number_of_puts); - puts_charge = ratio * report_after.total_customer_charge.puts; + let ratio2_puts = Perquintill::from_rational( + node_usage2.number_of_puts, + total_nodes_usage.number_of_puts, + ); + puts_charge = ratio2_puts * report_after.total_customer_charge.puts; - ratio = - Perbill::from_rational(node_usage2.number_of_gets, total_nodes_usage.number_of_gets); - gets_charge = ratio * report_after.total_customer_charge.gets; + let ratio2_gets = Perquintill::from_rational( + node_usage2.number_of_gets, + total_nodes_usage.number_of_gets, + ); + gets_charge = ratio2_gets * report_after.total_customer_charge.gets; - balance = Balances::free_balance(node2); - assert_eq!(balance, transfer_charge + storage_charge + puts_charge + gets_charge); + let balance_node2 = Balances::free_balance(node2); + assert_eq!(balance_node2, transfer_charge + storage_charge + puts_charge + gets_charge); + assert_eq!(report_reward.total_distributed_reward, balance_node1 + balance_node2); + // batch 2 assert_ok!(DdcPayouts::send_rewarding_providers_batch( RuntimeOrigin::signed(dac_account), cluster_id, @@ -1395,25 +1407,42 @@ fn send_rewarding_providers_batch_works() { payees2, )); - ratio = Perbill::from_rational( + let ratio3_transfer = Perquintill::from_rational( node_usage3.transferred_bytes, total_nodes_usage.transferred_bytes, ); - transfer_charge = ratio * report_after.total_customer_charge.transfer; + transfer_charge = ratio3_transfer * report_after.total_customer_charge.transfer; + + let ratio3_storage = + Perquintill::from_rational(node_usage3.stored_bytes, total_nodes_usage.stored_bytes); + storage_charge = ratio3_storage * report_after.total_customer_charge.storage; + + let ratio3_puts = Perquintill::from_rational( + node_usage3.number_of_puts, + total_nodes_usage.number_of_puts, + ); + puts_charge = ratio3_puts * report_after.total_customer_charge.puts; - ratio = Perbill::from_rational(node_usage3.stored_bytes, total_nodes_usage.stored_bytes); - storage_charge = ratio * report_after.total_customer_charge.storage; + let ratio3_gets = Perquintill::from_rational( + node_usage3.number_of_gets, + total_nodes_usage.number_of_gets, + ); + gets_charge = ratio3_gets * report_after.total_customer_charge.gets; - ratio = - Perbill::from_rational(node_usage3.number_of_puts, total_nodes_usage.number_of_puts); - puts_charge = ratio * report_after.total_customer_charge.puts; + report_reward = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let balance_node3 = Balances::free_balance(node3); + assert_eq!(balance_node3, transfer_charge + storage_charge + puts_charge + gets_charge); + assert_eq!( + report_reward.total_distributed_reward, + balance_node1 + balance_node2 + balance_node3 + ); - ratio = - Perbill::from_rational(node_usage3.number_of_gets, total_nodes_usage.number_of_gets); - gets_charge = ratio * report_after.total_customer_charge.gets; + let expected_amount_to_reward = report_reward.total_customer_charge.transfer + + report_reward.total_customer_charge.storage + + report_reward.total_customer_charge.puts + + report_reward.total_customer_charge.gets; - balance = Balances::free_balance(node3); - assert_eq!(balance, transfer_charge + storage_charge + puts_charge + gets_charge); + assert!(expected_amount_to_reward - report_reward.total_distributed_reward <= 20000); assert_ok!(DdcPayouts::end_rewarding_providers( RuntimeOrigin::signed(dac_account), @@ -1587,15 +1616,29 @@ fn end_rewarding_providers_works() { System::set_block_number(1); let dac_account = 2u128; - let user1 = 3u128; + let user1 = 1u128; let node1 = 33u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 0; let batch_index = 0; - let total_node_usage = NodeUsage::default(); - let payers = vec![(user1, CustomerUsage::default())]; - let payees = vec![(node1, NodeUsage::default())]; + let usage1 = CustomerUsage { + transferred_bytes: 23452345, + stored_bytes: 3345234523, + number_of_puts: 4456456345234523, + number_of_gets: 523423, + }; + + let node_usage1 = NodeUsage { + // CDN + Storage + transferred_bytes: usage1.transferred_bytes * 2 / 3, + stored_bytes: usage1.stored_bytes * 2 / 3, + number_of_puts: usage1.number_of_puts * 2 / 3, + number_of_gets: usage1.number_of_gets * 2 / 3, + }; + let total_node_usage = node_usage1.clone(); + let payers = vec![(user1, usage1)]; + let payees = vec![(node1, node_usage1)]; assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); diff --git a/pallets/ddc-staking/src/mock.rs b/pallets/ddc-staking/src/mock.rs index eaee9f844..9085b5ed5 100644 --- a/pallets/ddc-staking/src/mock.rs +++ b/pallets/ddc-staking/src/mock.rs @@ -20,7 +20,7 @@ use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - Perbill, + Perquintill, }; use sp_std::collections::btree_map::BTreeMap; @@ -146,9 +146,9 @@ impl ClusterVisitor for TestClusterVisitor { fn get_fees_params(_cluster_id: &ClusterId) -> Result { Ok(ClusterFeesParams { - treasury_share: Perbill::from_percent(1), - validators_share: Perbill::from_percent(10), - cluster_reserve_share: Perbill::from_percent(2), + treasury_share: Perquintill::from_percent(1), + validators_share: Perquintill::from_percent(10), + cluster_reserve_share: Perquintill::from_percent(2), }) } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 78c25e2f7..54b1c0c9e 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -5,7 +5,7 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::hash::H160; -use sp_runtime::{AccountId32, Perbill, RuntimeDebug}; +use sp_runtime::{AccountId32, Perquintill, RuntimeDebug}; pub type ClusterId = H160; pub type DdcEra = u32; pub type BucketId = u64; @@ -21,9 +21,9 @@ pub struct ClusterPricingParams { #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] pub struct ClusterFeesParams { - pub treasury_share: Perbill, - pub validators_share: Perbill, - pub cluster_reserve_share: Perbill, + pub treasury_share: Perquintill, + pub validators_share: Perquintill, + pub cluster_reserve_share: Perquintill, } #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]