diff --git a/Cargo.lock b/Cargo.lock index 1d8eec70e..c1460848c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1583,7 +1583,7 @@ dependencies = [ [[package]] name = "ddc-primitives" -version = "0.1.0" +version = "4.8.2" dependencies = [ "parity-scale-codec", "scale-info", @@ -1594,7 +1594,7 @@ dependencies = [ [[package]] name = "ddc-traits" -version = "0.1.0" +version = "4.8.2" dependencies = [ "ddc-primitives", "frame-support", diff --git a/pallets/ddc-clusters/Cargo.toml b/pallets/ddc-clusters/Cargo.toml index 5630b420b..def75665d 100644 --- a/pallets/ddc-clusters/Cargo.toml +++ b/pallets/ddc-clusters/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -ddc-primitives = { version = "0.1.0", default-features = false, path = "../../primitives" } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../../primitives" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31", optional = true } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/pallets/ddc-clusters/src/benchmarking.rs b/pallets/ddc-clusters/src/benchmarking.rs index cb9b47397..2405330d7 100644 --- a/pallets/ddc-clusters/src/benchmarking.rs +++ b/pallets/ddc-clusters/src/benchmarking.rs @@ -7,7 +7,7 @@ pub use frame_benchmarking::{ }; use frame_system::RawOrigin; use pallet_contracts::chain_extension::UncheckedFrom; -use sp_runtime::{AccountId32, Perbill}; +use sp_runtime::{AccountId32, Perquintill}; use sp_std::prelude::*; use testing_utils::*; @@ -26,9 +26,9 @@ benchmarks! { let user = account::("user", USER_SEED, 0u32); let cluster_params = ClusterParams { node_provider_auth_contract: Some(user.clone()) }; let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 100u32.into(), storage_chill_delay: 50u32.into(), storage_unbonding_delay: 50u32.into(), @@ -89,9 +89,9 @@ benchmarks! { let user = account::("user", USER_SEED, 0u32); let _ = config_cluster::(user, cluster_id); let new_cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 10u32.into(), storage_chill_delay: 5u32.into(), storage_unbonding_delay: 5u32.into(), diff --git a/pallets/ddc-clusters/src/mock.rs b/pallets/ddc-clusters/src/mock.rs index d06aa1837..911d4ce84 100644 --- a/pallets/ddc-clusters/src/mock.rs +++ b/pallets/ddc-clusters/src/mock.rs @@ -18,7 +18,7 @@ use sp_runtime::{ traits::{ BlakeTwo256, Convert, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify, }, - MultiSignature, Perbill, + MultiSignature, Perquintill, }; use crate::{self as pallet_ddc_clusters, *}; @@ -244,9 +244,9 @@ impl ExtBuilder { .assimilate_storage(&mut storage); 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, diff --git a/pallets/ddc-clusters/src/testing_utils.rs b/pallets/ddc-clusters/src/testing_utils.rs index efba60338..5acb0dc42 100644 --- a/pallets/ddc-clusters/src/testing_utils.rs +++ b/pallets/ddc-clusters/src/testing_utils.rs @@ -11,7 +11,7 @@ pub use frame_benchmarking::{ use frame_system::RawOrigin; use pallet_contracts::chain_extension::UncheckedFrom; use pallet_ddc_nodes::Node; -use sp_runtime::Perbill; +use sp_runtime::Perquintill; use sp_std::prelude::*; use crate::{Pallet as DdcClusters, *}; @@ -22,9 +22,9 @@ where { let cluster_params = ClusterParams { node_provider_auth_contract: Some(user.clone()) }; let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 100u32.into(), storage_chill_delay: 50u32.into(), storage_unbonding_delay: 50u32.into(), @@ -64,9 +64,9 @@ where }; let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 100u32.into(), storage_chill_delay: 50u32.into(), storage_unbonding_delay: 50u32.into(), diff --git a/pallets/ddc-clusters/src/tests.rs b/pallets/ddc-clusters/src/tests.rs index 5f33a4b8f..734e4f465 100644 --- a/pallets/ddc-clusters/src/tests.rs +++ b/pallets/ddc-clusters/src/tests.rs @@ -8,7 +8,7 @@ use ddc_traits::cluster::ClusterManager; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use frame_system::Config; use hex_literal::hex; -use sp_runtime::{traits::Hash, Perbill}; +use sp_runtime::{traits::Hash, Perquintill}; use super::{mock::*, *}; @@ -23,9 +23,9 @@ fn create_cluster_works() { let auth_contract = AccountId::from([3; 32]); 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, @@ -154,9 +154,9 @@ fn add_and_delete_node_works() { cluster_reserve_id.clone(), ClusterParams { node_provider_auth_contract: Some(cluster_manager_id.clone()) }, 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, @@ -374,9 +374,9 @@ fn set_cluster_params_works() { cluster_reserve_id.clone(), ClusterParams { node_provider_auth_contract: Some(auth_contract_1) }, 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, @@ -422,9 +422,9 @@ fn set_cluster_gov_params_works() { let auth_contract = AccountId::from([3; 32]); 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, @@ -463,9 +463,9 @@ fn set_cluster_gov_params_works() { ); let updated_gov_params = ClusterGovParams { - treasury_share: Perbill::from_float(0.06), - validators_share: Perbill::from_float(0.02), - cluster_reserve_share: Perbill::from_float(0.03), + treasury_share: Perquintill::from_float(0.06), + validators_share: Perquintill::from_float(0.02), + cluster_reserve_share: Perquintill::from_float(0.03), storage_bond_size: 1000, storage_chill_delay: 500, storage_unbonding_delay: 500, @@ -537,9 +537,9 @@ fn cluster_visitor_works() { let auth_contract = AccountId::from([3; 32]); 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, @@ -585,9 +585,9 @@ fn cluster_visitor_works() { assert_eq!( >::get_fees_params(&cluster_id).unwrap(), ClusterFeesParams { - 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) } ); @@ -646,9 +646,9 @@ fn cluster_creator_works() { let auth_contract = AccountId::from([3; 32]); 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), storage_bond_size: 100, storage_chill_delay: 50, storage_unbonding_delay: 50, diff --git a/pallets/ddc-customers/Cargo.toml b/pallets/ddc-customers/Cargo.toml index 25bbd10c6..a723c3c66 100644 --- a/pallets/ddc-customers/Cargo.toml +++ b/pallets/ddc-customers/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31", optional = true } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } @@ -17,8 +18,8 @@ rand_chacha = { version = "0.2", default-features = false, optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # Cere -ddc-primitives = { version = "0.1.0", default-features = false, path = "../../primitives" } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../../primitives" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } [dev-dependencies] frame-benchmarking = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/pallets/ddc-customers/src/benchmarking.rs b/pallets/ddc-customers/src/benchmarking.rs index 87da166fb..b7794cc13 100644 --- a/pallets/ddc-customers/src/benchmarking.rs +++ b/pallets/ddc-customers/src/benchmarking.rs @@ -4,7 +4,7 @@ use ddc_primitives::{ClusterGovParams, ClusterId, ClusterParams}; use frame_benchmarking::{account, benchmarks, whitelist_account}; use frame_support::traits::Currency; -use sp_runtime::Perbill; +use sp_runtime::Perquintill; use sp_std::prelude::*; use super::*; @@ -21,11 +21,10 @@ benchmarks! { create_bucket { let cluster_id = ClusterId::from([1; 20]); let user = account::("user", USER_SEED, 0u32); - let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 100u32.into(), storage_chill_delay: 50u32.into(), storage_unbonding_delay: 50u32.into(), diff --git a/pallets/ddc-customers/src/lib.rs b/pallets/ddc-customers/src/lib.rs index 181821ea5..482f9465b 100644 --- a/pallets/ddc-customers/src/lib.rs +++ b/pallets/ddc-customers/src/lib.rs @@ -12,9 +12,7 @@ pub(crate) mod mock; #[cfg(test)] mod tests; -use core::fmt::Debug; - -use codec::{Decode, Encode, HasCompact}; +use codec::{Decode, Encode}; use ddc_primitives::{BucketId, ClusterId}; use ddc_traits::{ cluster::{ClusterCreator, ClusterVisitor}, @@ -27,8 +25,9 @@ use frame_support::{ }; pub use pallet::*; use scale_info::TypeInfo; +use sp_io::hashing::blake2_128; use sp_runtime::{ - traits::{AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Saturating, Zero}, + traits::{AccountIdConversion, CheckedAdd, CheckedSub, Saturating, Zero}, RuntimeDebug, SaturatedConversion, }; use sp_std::prelude::*; @@ -45,17 +44,13 @@ parameter_types! { /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct UnlockChunk -where - Balance: HasCompact, - BlockNumber: Clone, -{ +pub struct UnlockChunk { /// Amount of funds to be unlocked. #[codec(compact)] - value: Balance, + value: BalanceOf, /// Block number at which point it'll be unlocked. #[codec(compact)] - block: BlockNumber, + block: T::BlockNumber, } #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] @@ -73,33 +68,28 @@ pub struct BucketParams { #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct AccountsLedger { +pub struct AccountsLedger { /// The owner account whose balance is actually locked and can be used to pay for DDC network /// usage. - pub owner: AccountId, + pub owner: T::AccountId, /// The total amount of the owner's balance that we are currently accounting for. /// It's just `active` plus all the `unlocking` balances. #[codec(compact)] - pub total: Balance, + pub total: BalanceOf, /// The total amount of the owner's balance that will be accessible for DDC network payouts in /// any forthcoming rounds. #[codec(compact)] - pub active: Balance, + pub active: BalanceOf, /// Any balance that is becoming free, which may eventually be transferred out of the owner /// (assuming that the content owner has to pay for network usage). It is assumed that this /// will be treated as a first in, first out queue where the new (higher value) eras get pushed /// on the back. - pub unlocking: BoundedVec, MaxUnlockingChunks>, + pub unlocking: BoundedVec, MaxUnlockingChunks>, } -impl< - AccountId, - Balance: HasCompact + Copy + Saturating + AtLeast32BitUnsigned + Zero + Debug, - T: Config, - > AccountsLedger -{ +impl AccountsLedger { /// Initializes the default object using the given owner. - pub fn default_from(owner: AccountId) -> Self { + pub fn default_from(owner: T::AccountId) -> Self { Self { owner, total: Zero::zero(), active: Zero::zero(), unlocking: Default::default() } } @@ -107,11 +97,10 @@ impl< /// total by the sum of their balances. fn consolidate_unlocked(self, current_block: T::BlockNumber) -> Self { let mut total = self.total; - let unlocking: BoundedVec<_, _> = self + let unlocking_result: Result, _> = self .unlocking .into_iter() .filter(|chunk| { - log::debug!("Chunk era: {:?}", chunk.block); if chunk.block > current_block { true } else { @@ -120,43 +109,13 @@ impl< } }) .collect::>() - .try_into() - .expect( - "filtering items from a bounded vec always leaves length less than bounds. qed", - ); - - Self { owner: self.owner, total, active: self.active, unlocking } - } - - /// Charge funds that were scheduled for unlocking. - /// - /// Returns the updated ledger, and the amount actually charged. - fn charge_unlocking(mut self, value: Balance) -> Result<(Self, Balance), Error> { - let mut unlocking_balance = Balance::zero(); - - while let Some(last) = self.unlocking.last_mut() { - let temp = unlocking_balance - .checked_add(&last.value) - .ok_or(Error::::ArithmeticOverflow)?; - if temp <= value { - unlocking_balance = temp; - self.unlocking.pop(); - } else { - let diff = - value.checked_sub(&unlocking_balance).ok_or(Error::::ArithmeticUnderflow)?; - - unlocking_balance = - unlocking_balance.checked_add(&diff).ok_or(Error::::ArithmeticOverflow)?; - last.value = - last.value.checked_sub(&diff).ok_or(Error::::ArithmeticUnderflow)?; - } + .try_into(); - if unlocking_balance >= value { - break - } + if let Ok(unlocking) = unlocking_result { + Self { owner: self.owner, total, active: self.active, unlocking } + } else { + panic!("Failed to filter unlocking"); } - - Ok((self, unlocking_balance)) } } @@ -190,12 +149,7 @@ pub mod pallet { /// Map from all (unlocked) "owner" accounts to the info regarding the staking. #[pallet::storage] #[pallet::getter(fn ledger)] - pub type Ledger = StorageMap< - _, - Blake2_128Concat, - T::AccountId, - AccountsLedger, T>, - >; + pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, AccountsLedger>; #[pallet::type_value] pub fn DefaultBucketCount() -> BucketId { @@ -266,13 +220,14 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { + pub feeder_account: Option, pub buckets: Vec<(ClusterId, T::AccountId, BalanceOf, bool)>, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - GenesisConfig { buckets: Default::default() } + GenesisConfig { feeder_account: None, buckets: Default::default() } } } @@ -281,8 +236,19 @@ pub mod pallet { fn build(&self) { let account_id = >::account_id(); let min = ::Currency::minimum_balance(); - if ::Currency::free_balance(&account_id) < min { - let _ = ::Currency::make_free_balance_be(&account_id, min); + + let balance = ::Currency::free_balance(&account_id); + if balance < min { + if let Some(vault) = &self.feeder_account { + let _ = ::Currency::transfer( + vault, + &account_id, + min - balance, + ExistenceRequirement::AllowDeath, + ); + } else { + let _ = ::Currency::make_free_balance_be(&account_id, min); + } } for &(ref cluster_id, ref owner_id, ref deposit, ref is_public) in &self.buckets { @@ -300,7 +266,7 @@ pub mod pallet { }; >::insert(cur_bucket_id, bucket); - let ledger = AccountsLedger::, T> { + let ledger = AccountsLedger:: { owner: owner_id.clone(), total: *deposit, active: *deposit, @@ -481,7 +447,6 @@ pub mod pallet { // This was the consequence of a partial deposit unlock. just update the ledger and // move on. >::insert(&owner, &ledger); - // This is only an update, so we use less overall weight. Some(::WeightInfo::withdraw_unlocked_deposit_update()) }; @@ -497,13 +462,11 @@ pub mod pallet { let value = old_total.checked_sub(&ledger.total).ok_or(Error::::ArithmeticUnderflow)?; - let account_id = Self::account_id(); - ::Currency::transfer( - &account_id, + &Self::account_id(), &owner, value, - ExistenceRequirement::KeepAlive, + ExistenceRequirement::AllowDeath, )?; Self::deposit_event(Event::::Withdrawn(owner, value)); } @@ -538,18 +501,26 @@ pub mod pallet { pub fn account_id() -> T::AccountId { T::PalletId::get().into_account_truncating() } + + pub fn sub_account_id(account_id: &T::AccountId) -> T::AccountId { + let hash = blake2_128(&account_id.encode()); + + // hash is 28 bytes + T::PalletId::get().into_sub_account_truncating(hash) + } + /// Update the ledger for a owner. /// /// This will also deposit the funds to pallet. fn update_ledger_and_deposit( owner: &T::AccountId, - ledger: &AccountsLedger, T>, + ledger: &AccountsLedger, ) -> DispatchResult { ::Currency::transfer( owner, &Self::account_id(), ledger.total, - ExistenceRequirement::KeepAlive, + ExistenceRequirement::AllowDeath, )?; >::insert(owner, ledger); @@ -569,6 +540,42 @@ pub mod pallet { Ok(()) } + + /// Charge funds that were scheduled for unlocking. + /// + /// Returns the updated ledger, and the amount actually charged. + fn charge_unlocking( + mut ledger: AccountsLedger, + value: BalanceOf, + ) -> Result<(AccountsLedger, BalanceOf), Error> { + let mut unlocking_balance = BalanceOf::::zero(); + + while let Some(last) = ledger.unlocking.last_mut() { + let temp = unlocking_balance + .checked_add(&last.value) + .ok_or(Error::::ArithmeticOverflow)?; + if temp <= value { + unlocking_balance = temp; + ledger.unlocking.pop(); + } else { + let diff = value + .checked_sub(&unlocking_balance) + .ok_or(Error::::ArithmeticUnderflow)?; + + unlocking_balance = unlocking_balance + .checked_add(&diff) + .ok_or(Error::::ArithmeticOverflow)?; + last.value = + last.value.checked_sub(&diff).ok_or(Error::::ArithmeticUnderflow)?; + } + + if unlocking_balance >= value { + break + } + } + + Ok((ledger, unlocking_balance)) + } } impl CustomerCharger for Pallet { @@ -591,8 +598,6 @@ pub mod pallet { .total .checked_sub(&amount_to_deduct) .ok_or(Error::::ArithmeticUnderflow)?; - - >::insert(&content_owner, &ledger); } else { let diff = amount_to_deduct .checked_sub(&ledger.active) @@ -605,11 +610,10 @@ pub mod pallet { .ok_or(Error::::ArithmeticUnderflow)?; ledger.active = BalanceOf::::zero(); - let (ledger, charged) = ledger.charge_unlocking(diff)?; + let (_ledger, charged) = Self::charge_unlocking(ledger, diff)?; + ledger = _ledger; actually_charged.checked_add(&charged).ok_or(Error::::ArithmeticUnderflow)?; - - >::insert(&content_owner, &ledger); } ::Currency::transfer( @@ -619,6 +623,7 @@ pub mod pallet { ExistenceRequirement::AllowDeath, )?; + >::insert(&content_owner, &ledger); // update state after successful transfer Self::deposit_event(Event::::Charged(content_owner, amount_to_deduct)); Ok(actually_charged.saturated_into::()) diff --git a/pallets/ddc-customers/src/mock.rs b/pallets/ddc-customers/src/mock.rs index 3e779f06c..7b07b6b06 100644 --- a/pallets/ddc-customers/src/mock.rs +++ b/pallets/ddc-customers/src/mock.rs @@ -9,7 +9,7 @@ use ddc_traits::cluster::{ }; use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU32, ConstU64, Everything}, + traits::{ConstU32, ConstU64, Everything, GenesisBuild}, weights::constants::RocksDbWeight, }; use frame_system::mocking::{MockBlock, MockUncheckedExtrinsic}; @@ -18,13 +18,13 @@ use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - DispatchResult, Perbill, + DispatchResult, Perquintill, }; use crate::{self as pallet_ddc_customers, *}; /// The AccountId alias in this test module. -pub(crate) type AccountId = u64; +pub(crate) type AccountId = u128; pub(crate) type AccountIndex = u64; pub(crate) type BlockNumber = u64; pub(crate) type Balance = u128; @@ -147,9 +147,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), }) } @@ -223,11 +223,17 @@ impl ExtBuilder { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let _ = pallet_balances::GenesisConfig:: { + let _balance_genesis = pallet_balances::GenesisConfig:: { balances: vec![(1, 100), (2, 100), (3, 1000)], } .assimilate_storage(&mut storage); + let _customer_genesis = pallet_ddc_customers::GenesisConfig:: { + feeder_account: None, + buckets: Default::default(), + } + .assimilate_storage(&mut storage); + TestExternalities::new(storage) } pub fn build_and_execute(self, test: impl FnOnce()) { diff --git a/pallets/ddc-customers/src/tests.rs b/pallets/ddc-customers/src/tests.rs index e88846a5c..9a7738ca5 100644 --- a/pallets/ddc-customers/src/tests.rs +++ b/pallets/ddc-customers/src/tests.rs @@ -2,7 +2,6 @@ use ddc_primitives::ClusterId; use frame_support::{assert_noop, assert_ok}; -use frame_system::Config; use super::{mock::*, *}; @@ -164,8 +163,8 @@ fn charge_content_owner_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let account_3 = 3; - let vault = 4; + let account_3: u128 = 3; + let vault: u128 = 4; let deposit = 100_u128; let balance_before_deposit = Balances::free_balance(account_3); @@ -175,7 +174,7 @@ fn charge_content_owner_works() { assert_eq!(balance_before_deposit - deposit, balance_after_deposit); let pallet_balance = Balances::free_balance(DdcCustomers::account_id()); - assert_eq!(deposit, pallet_balance); + assert_eq!(deposit, pallet_balance - Balances::minimum_balance()); // Check storage assert_eq!( @@ -229,7 +228,10 @@ fn charge_content_owner_works() { }) ); - assert_eq!(0, Balances::free_balance(DdcCustomers::account_id())); + assert_eq!( + 0, + Balances::free_balance(DdcCustomers::account_id()) - Balances::minimum_balance() + ); assert_eq!(charge_result, deposit - charge1); assert_ok!(DdcCustomers::deposit_extra(RuntimeOrigin::signed(account_3), deposit)); @@ -243,7 +245,10 @@ fn charge_content_owner_works() { }) ); - assert_eq!(deposit, Balances::free_balance(DdcCustomers::account_id())); + assert_eq!( + deposit, + Balances::free_balance(DdcCustomers::account_id()) - Balances::minimum_balance() + ); }) } @@ -264,14 +269,7 @@ fn unlock_and_withdraw_deposit_works() { assert_ok!(DdcCustomers::unlock_deposit(RuntimeOrigin::signed(account_1), 1_u128)); System::set_block_number(2); - let mut unlocking_chunks: BoundedVec< - UnlockChunk::BlockNumber>, - MaxUnlockingChunks, - > = Default::default(); - match unlocking_chunks.try_push(UnlockChunk { value: 1, block: 11 }) { - Ok(_) => (), - Err(_) => println!("No more chunks"), - }; + let unlocking_chunks = vec![UnlockChunk { value: 1, block: 11 }]; // Check storage assert_eq!( DdcCustomers::ledger(&1), @@ -279,7 +277,7 @@ fn unlock_and_withdraw_deposit_works() { owner: account_1, total: 35_u128, active: 34_u128, - unlocking: unlocking_chunks.clone(), + unlocking: BoundedVec::try_from(unlocking_chunks).unwrap(), }) ); diff --git a/pallets/ddc-customers/src/weights.rs b/pallets/ddc-customers/src/weights.rs index 09351dbe1..0a3c999dc 100644 --- a/pallets/ddc-customers/src/weights.rs +++ b/pallets/ddc-customers/src/weights.rs @@ -1,9 +1,9 @@ //! Autogenerated weights for pallet_ddc_customers //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Yahors-MacBook-Pro.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2023-12-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bench`, CPU: `DO-Premium-AMD` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Interpreted, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/release/cere @@ -43,47 +43,47 @@ impl WeightInfo for SubstrateWeight { // Storage: DdcClusters Clusters (r:1 w:0) // Storage: DdcCustomers Buckets (r:0 w:1) fn create_bucket() -> Weight { - Weight::from_ref_time(17_000_000_u64) + Weight::from_ref_time(156_518_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn deposit() -> Weight { - Weight::from_ref_time(28_000_000_u64) + Weight::from_ref_time(439_562_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn deposit_extra() -> Weight { - Weight::from_ref_time(29_000_000_u64) + Weight::from_ref_time(582_699_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) fn unlock_deposit() -> Weight { - Weight::from_ref_time(16_000_000_u64) + Weight::from_ref_time(208_316_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unlocked_deposit_update() -> Weight { - Weight::from_ref_time(30_000_000_u64) + Weight::from_ref_time(451_983_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unlocked_deposit_kill() -> Weight { - Weight::from_ref_time(32_000_000_u64) + Weight::from_ref_time(599_908_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Buckets (r:1 w:1) fn set_bucket_params() -> Weight { - Weight::from_ref_time(14_000_000_u64) + Weight::from_ref_time(155_437_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -95,48 +95,48 @@ impl WeightInfo for () { // Storage: DdcClusters Clusters (r:1 w:0) // Storage: DdcCustomers Buckets (r:0 w:1) fn create_bucket() -> Weight { - Weight::from_ref_time(17_000_000_u64) + Weight::from_ref_time(156_518_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn deposit() -> Weight { - Weight::from_ref_time(28_000_000_u64) + Weight::from_ref_time(439_562_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn deposit_extra() -> Weight { - Weight::from_ref_time(29_000_000_u64) + Weight::from_ref_time(582_699_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) fn unlock_deposit() -> Weight { - Weight::from_ref_time(16_000_000_u64) + Weight::from_ref_time(208_316_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unlocked_deposit_update() -> Weight { - Weight::from_ref_time(30_000_000_u64) + Weight::from_ref_time(451_983_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Ledger (r:1 w:1) // Storage: System Account (r:1 w:1) fn withdraw_unlocked_deposit_kill() -> Weight { - Weight::from_ref_time(32_000_000_u64) + Weight::from_ref_time(599_908_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } // Storage: DdcCustomers Buckets (r:1 w:1) fn set_bucket_params() -> Weight { - Weight::from_ref_time(14_000_000_u64) + Weight::from_ref_time(155_437_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } -} +} \ No newline at end of file diff --git a/pallets/ddc-nodes/Cargo.toml b/pallets/ddc-nodes/Cargo.toml index 9369fd55e..e2a615823 100644 --- a/pallets/ddc-nodes/Cargo.toml +++ b/pallets/ddc-nodes/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -ddc-primitives = { version = "0.1.0", default-features = false, path = "../../primitives" } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../../primitives" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31", optional = true } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/pallets/ddc-payouts/Cargo.toml b/pallets/ddc-payouts/Cargo.toml index f7f7e28be..6122a256c 100644 --- a/pallets/ddc-payouts/Cargo.toml +++ b/pallets/ddc-payouts/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" [dependencies] byte-unit = { version = "4.0.19", default-features = false, features = ["u128"] } codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -ddc-primitives = { version = "0.1.0", default-features = false, path = "../../primitives" } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../../primitives" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31", optional = true } frame-election-provider-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/pallets/ddc-payouts/src/benchmarking.rs b/pallets/ddc-payouts/src/benchmarking.rs index 4690b29ac..3967a85cd 100644 --- a/pallets/ddc-payouts/src/benchmarking.rs +++ b/pallets/ddc-payouts/src/benchmarking.rs @@ -3,6 +3,7 @@ use ddc_primitives::{ClusterGovParams, ClusterId, ClusterParams}; pub use frame_benchmarking::{account, benchmarks, whitelist_account}; use frame_system::RawOrigin; +use sp_runtime::Perquintill; use sp_std::prelude::*; use super::*; @@ -61,9 +62,9 @@ fn create_default_cluster(cluster_id: ClusterId) { let cluster_reserve = create_account::("cr", 0, 0); let cluster_params = ClusterParams { node_provider_auth_contract: Default::default() }; let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::from_percent(5), - validators_share: Perbill::from_percent(10), - cluster_reserve_share: Perbill::from_percent(15), + treasury_share: Perquintill::from_percent(5), + validators_share: Perquintill::from_percent(10), + cluster_reserve_share: Perquintill::from_percent(15), unit_per_mb_stored: CERE, unit_per_mb_streamed: CERE, unit_per_put_request: CERE, @@ -349,8 +350,8 @@ benchmarks! { let total_node_usage = NodeUsage { transferred_bytes: 200000000u64.saturating_mul(b.into()), // 200 mb per provider stored_bytes: 100000000u64.saturating_mul(b.into()), // 100 mb per provider - number_of_gets: 10u128.saturating_mul(b.into()), // 10 gets per provider - number_of_puts: 5u128.saturating_mul(b.into()), // 5 puts per provider + number_of_gets: 10u64.saturating_mul(b.into()), // 10 gets per provider + number_of_puts: 10u64.saturating_mul(b.into()), // 5 puts per provider }; let charging_max_batch_index = 0; let mut charging_processed_batches : BoundedBTreeSet = BoundedBTreeSet::default(); diff --git a/pallets/ddc-payouts/src/lib.rs b/pallets/ddc-payouts/src/lib.rs index 51eb7bc15..8dbd206d5 100644 --- a/pallets/ddc-payouts/src/lib.rs +++ b/pallets/ddc-payouts/src/lib.rs @@ -25,7 +25,7 @@ pub(crate) mod mock; #[cfg(test)] mod tests; -use ddc_primitives::{ClusterId, DdcEra}; +use ddc_primitives::{ClusterId, DdcEra, MILLICENTS}; use ddc_traits::{ cluster::{ClusterCreator as ClusterCreatorType, ClusterVisitor as ClusterVisitorType}, customer::{ @@ -43,7 +43,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; pub use pallet::*; -use sp_runtime::{PerThing, Perbill}; +use sp_runtime::{traits::Convert, PerThing, Perquintill}; use sp_std::prelude::*; type BatchIndex = u16; @@ -53,8 +53,8 @@ type BatchIndex = u16; pub struct CustomerUsage { pub transferred_bytes: u64, pub stored_bytes: u64, - pub number_of_puts: u128, - pub number_of_gets: u128, + pub number_of_puts: u64, + pub number_of_gets: u64, } /// Stores usage of node provider @@ -62,8 +62,8 @@ pub struct CustomerUsage { pub struct NodeUsage { pub transferred_bytes: u64, pub stored_bytes: u64, - pub number_of_puts: u128, - pub number_of_gets: u128, + pub number_of_puts: u64, + pub number_of_gets: u64, } /// Stores reward in tokens(units) of node provider as per NodeUsage @@ -96,8 +96,14 @@ pub struct CustomerCharge { pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub type VoteScoreOf = + <::NominatorsAndValidatorsList as frame_election_provider_support::SortedListProvider< + ::AccountId, + >>::Score; + parameter_types! { pub MaxBatchesCount: u16 = 1000; + pub MaxDust: u128 = MILLICENTS; pub MaxBatchSize: u16 = 1000; } @@ -124,9 +130,10 @@ pub mod pallet { type CustomerDepositor: CustomerDepositorType; type TreasuryVisitor: PalletVisitorType; type ClusterVisitor: ClusterVisitorType; - type ValidatorList: SortedListProvider; + type NominatorsAndValidatorsList: SortedListProvider; type ClusterCreator: ClusterCreatorType>; type WeightInfo: WeightInfo; + type VoteScoreToU64: Convert, u64>; } #[pallet::event] @@ -190,6 +197,19 @@ pub mod pallet { node_provider_id: T::AccountId, amount: u128, }, + NotDistributedReward { + cluster_id: ClusterId, + era: DdcEra, + node_provider_id: T::AccountId, + expected_reward: u128, + distributed_reward: BalanceOf, + }, + NotDistributedOverallReward { + cluster_id: ClusterId, + era: DdcEra, + expected_reward: u128, + total_distributed_reward: u128, + }, RewardingFinished { cluster_id: ClusterId, era: DdcEra, @@ -212,12 +232,12 @@ pub mod pallet { BatchIndexAlreadyProcessed, BatchIndexIsOutOfRange, BatchesMissed, - NotDistributedBalance, BatchIndexOverflow, BoundedVecOverflow, ArithmeticOverflow, NotExpectedClusterState, BatchSizeIsOutOfBounds, + ScoreRetrievalError, } #[pallet::storage] @@ -240,6 +260,11 @@ pub mod pallet { pub type DebtorCustomers = StorageDoubleMap<_, Blake2_128Concat, ClusterId, Blake2_128Concat, T::AccountId, u128>; + #[pallet::storage] + #[pallet::getter(fn owing_providers)] + pub type OwingProviders = + StorageDoubleMap<_, Blake2_128Concat, ClusterId, Blake2_128Concat, T::AccountId, u128>; + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] #[scale_info(skip_type_params(T))] pub struct BillingReport { @@ -286,33 +311,6 @@ pub mod pallet { Finalized = 7, } - #[pallet::genesis_config] - pub struct GenesisConfig { - pub authorised_caller: Option, - pub debtor_customers: Vec<(ClusterId, T::AccountId, u128)>, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - GenesisConfig { - authorised_caller: Default::default(), - debtor_customers: Default::default(), - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - AuthorisedCaller::::set(self.authorised_caller.clone()); - - for (cluster_id, customer_id, debt) in &self.debtor_customers { - DebtorCustomers::::insert(cluster_id, customer_id, debt); - } - } - } - #[pallet::call] impl Pallet { #[pallet::weight(T::WeightInfo::set_authorised_caller())] @@ -343,13 +341,11 @@ pub mod pallet { Error::::NotExpectedState ); - let mut billing_report = BillingReport:: { - vault: Self::sub_account_id(cluster_id, era), + let billing_report = BillingReport:: { + vault: Self::account_id(), state: State::Initialized, ..Default::default() }; - billing_report.vault = Self::sub_account_id(cluster_id, era); - billing_report.state = State::Initialized; ActiveBillingReports::::insert(cluster_id, era, billing_report); Self::deposit_event(Event::::BillingReportInitialized { cluster_id, era }); @@ -468,8 +464,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; @@ -682,6 +680,7 @@ pub mod pallet { Error::::BatchIndexAlreadyProcessed ); + let max_dust = MaxDust::get().saturated_into::>(); let mut updated_billing_report = billing_report.clone(); for payee in payees { let node_reward = get_node_reward::( @@ -700,19 +699,40 @@ pub mod pallet { .ok_or(Error::::ArithmeticOverflow)?; let node_provider_id = payee.0; - let reward: BalanceOf = amount_to_reward.saturated_into::>(); + if amount_to_reward > 0 { + let mut reward: BalanceOf = + amount_to_reward.saturated_into::>(); + + let vault_balance = ::Currency::free_balance( + &updated_billing_report.vault, + ) - ::Currency::minimum_balance(); + + if reward > vault_balance { + if reward - vault_balance > max_dust { + Self::deposit_event(Event::::NotDistributedReward { + cluster_id, + era, + node_provider_id: node_provider_id.clone(), + expected_reward: amount_to_reward, + distributed_reward: vault_balance, + }); + } + + reward = vault_balance; + } - ::Currency::transfer( - &updated_billing_report.vault, - &node_provider_id, - reward, - ExistenceRequirement::AllowDeath, - )?; + ::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)?; + 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, @@ -754,6 +774,26 @@ 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)?; + + if expected_amount_to_reward - billing_report.total_distributed_reward > MaxDust::get() + { + Self::deposit_event(Event::::NotDistributedOverallReward { + cluster_id, + era, + expected_reward: expected_amount_to_reward, + total_distributed_reward: billing_report.total_distributed_reward, + }); + } + billing_report.state = State::ProvidersRewarded; ActiveBillingReports::::insert(cluster_id, era, billing_report); @@ -775,20 +815,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(); @@ -829,20 +855,41 @@ pub mod pallet { ) } + fn get_current_exposure_ratios( + ) -> Result, DispatchError> { + let mut total_score = 0; + let mut individual_scores: Vec<(T::AccountId, u64)> = Vec::new(); + for staker_id in T::NominatorsAndValidatorsList::iter() { + let s = T::NominatorsAndValidatorsList::get_score(&staker_id) + .map_err(|_| Error::::ScoreRetrievalError)?; + let score = T::VoteScoreToU64::convert(s); + total_score += score; + + individual_scores.push((staker_id, score)); + } + + let mut result = Vec::new(); + for (staker_id, score) in individual_scores { + let ratio = Perquintill::from_rational(score, total_score); + result.push((staker_id, ratio)); + } + + Ok(result) + } + fn charge_validator_fees( validators_fee: u128, vault: &T::AccountId, ) -> DispatchResult { - let amount_to_deduct = validators_fee - .checked_div(T::ValidatorList::count().try_into().unwrap()) - .ok_or(Error::::ArithmeticOverflow)? - .saturated_into::>(); + let stakers = get_current_exposure_ratios::()?; + + for (staker_id, ratio) in stakers.iter() { + let amount_to_deduct = *ratio * validators_fee; - for validator_account_id in T::ValidatorList::iter() { ::Currency::transfer( vault, - &validator_account_id, - amount_to_deduct, + staker_id, + amount_to_deduct.saturated_into::>(), ExistenceRequirement::AllowDeath, )?; } @@ -857,20 +904,26 @@ pub mod pallet { ) -> Option { let mut node_reward = NodeReward::default(); - let mut ratio = Perbill::from_rational( - node_usage.transferred_bytes, - total_nodes_usage.transferred_bytes, + let mut ratio = Perquintill::from_rational( + node_usage.transferred_bytes as u128, + total_nodes_usage.transferred_bytes as u128, ); + // 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 as u128, + total_nodes_usage.stored_bytes as u128, + ); 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) @@ -899,13 +952,11 @@ pub mod pallet { })() .ok_or(Error::::ArithmeticOverflow)?; - total.gets = usage - .number_of_gets + total.gets = (usage.number_of_gets as u128) .checked_mul(pricing.unit_per_get_request) .ok_or(Error::::ArithmeticOverflow)?; - total.puts = usage - .number_of_puts + total.puts = (usage.number_of_puts as u128) .checked_mul(pricing.unit_per_put_request) .ok_or(Error::::ArithmeticOverflow)?; @@ -928,7 +979,55 @@ pub mod pallet { Ok(()) } + #[pallet::genesis_config] + pub struct GenesisConfig { + pub feeder_account: Option, + pub authorised_caller: Option, + pub debtor_customers: Vec<(ClusterId, T::AccountId, u128)>, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { + feeder_account: None, + authorised_caller: Default::default(), + debtor_customers: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + let account_id = >::account_id(); + let min = ::Currency::minimum_balance(); + let balance = ::Currency::free_balance(&account_id); + if balance < min { + if let Some(vault) = &self.feeder_account { + let _ = ::Currency::transfer( + vault, + &account_id, + min - balance, + ExistenceRequirement::AllowDeath, + ); + } else { + let _ = ::Currency::make_free_balance_be(&account_id, min); + } + } + + AuthorisedCaller::::set(self.authorised_caller.clone()); + for (cluster_id, customer_id, debt) in &self.debtor_customers { + DebtorCustomers::::insert(cluster_id, customer_id, debt); + } + } + } + impl Pallet { + pub fn account_id() -> T::AccountId { + T::PalletId::get().into_account_truncating() + } + pub fn sub_account_id(cluster_id: ClusterId, era: DdcEra) -> T::AccountId { let mut bytes = Vec::new(); bytes.extend_from_slice(&cluster_id[..]); diff --git a/pallets/ddc-payouts/src/mock.rs b/pallets/ddc-payouts/src/mock.rs index 3ef864f9a..9b01f98a4 100644 --- a/pallets/ddc-payouts/src/mock.rs +++ b/pallets/ddc-payouts/src/mock.rs @@ -4,7 +4,7 @@ use ddc_primitives::{ ClusterBondingParams, ClusterFeesParams, ClusterGovParams, ClusterParams, ClusterPricingParams, - NodeType, + NodeType, DOLLARS, }; use ddc_traits::{ cluster::{ClusterCreator, ClusterVisitor, ClusterVisitorError}, @@ -13,10 +13,8 @@ use ddc_traits::{ }; use frame_election_provider_support::SortedListProvider; use frame_support::{ - construct_runtime, - dispatch::DispatchError, - parameter_types, - traits::{ConstU32, ConstU64, Everything}, + construct_runtime, parameter_types, + traits::{ConstU32, ConstU64, Everything, Randomness}, weights::constants::RocksDbWeight, PalletId, }; @@ -25,14 +23,15 @@ use sp_core::H256; use sp_io::TestExternalities; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Identity, IdentityLookup}, + DispatchError, Perquintill, }; use sp_std::prelude::*; use crate::{self as pallet_ddc_payouts, *}; /// The AccountId alias in this test module. -pub type AccountId = u64; +pub type AccountId = u128; pub(crate) type AccountIndex = u64; pub(crate) type BlockNumber = u64; pub(crate) type Balance = u128; @@ -50,14 +49,31 @@ construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - DdcPayouts: pallet_ddc_payouts::{Pallet, Call, Storage, Event}, + DdcPayouts: pallet_ddc_payouts::{Pallet, Call, Storage, Config, Event}, } ); +pub static MAX_DUST: u16 = 100; + parameter_types! { pub static ExistentialDeposit: Balance = 1; } +#[derive(Default, Clone)] +pub struct MockRandomness(H256); + +impl Randomness for MockRandomness { + fn random(subject: &[u8]) -> (H256, BlockNumber) { + let (mut r, b) = Self::random_seed(); + r.as_mut()[0..subject.len()].copy_from_slice(subject); + (r, b) + } + + fn random_seed() -> (H256, BlockNumber) { + (H256::default(), BlockNumber::default()) + } +} + impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); @@ -109,8 +125,10 @@ impl crate::pallet::Config for Test { type CustomerDepositor = TestCustomerDepositor; type ClusterVisitor = TestClusterVisitor; type TreasuryVisitor = TestTreasuryVisitor; - type ValidatorList = TestValidatorVisitor; + type NominatorsAndValidatorsList = TestValidatorVisitor; type ClusterCreator = TestClusterCreator; + + type VoteScoreToU64 = Identity; type WeightInfo = (); } @@ -121,10 +139,28 @@ impl CustomerCharger for TestCustomerCharger { billing_vault: T::AccountId, amount: u128, ) -> Result { - ensure!(amount > 1_000_000, DispatchError::BadOrigin); // any error will do - let mut amount_to_charge = amount; - if amount_to_charge < 50_000_000 { + let mut temp = ACCOUNT_ID_1.to_ne_bytes(); + let account_1 = T::AccountId::decode(&mut &temp[..]).unwrap(); + temp = ACCOUNT_ID_2.to_ne_bytes(); + let account_2 = T::AccountId::decode(&mut &temp[..]).unwrap(); + temp = ACCOUNT_ID_3.to_ne_bytes(); + let account_3 = T::AccountId::decode(&mut &temp[..]).unwrap(); + temp = ACCOUNT_ID_4.to_ne_bytes(); + let account_4 = T::AccountId::decode(&mut &temp[..]).unwrap(); + temp = ACCOUNT_ID_5.to_ne_bytes(); + let account_5 = T::AccountId::decode(&mut &temp[..]).unwrap(); + + if content_owner == account_1 || + content_owner == account_2 || + content_owner == account_3 || + content_owner == account_4 || + content_owner == account_5 + { + ensure!(amount > 1_000_000, DispatchError::BadOrigin); // any error will do + } + + if amount_to_charge < 50_000_000 && content_owner == account_3 { amount_to_charge = PARTIAL_CHARGE; // for user 3 } @@ -140,6 +176,11 @@ impl CustomerCharger for TestCustomerCharger { } } +pub const ACCOUNT_ID_1: AccountId = 1; +pub const ACCOUNT_ID_2: AccountId = 2; +pub const ACCOUNT_ID_3: AccountId = 3; +pub const ACCOUNT_ID_4: AccountId = 4; +pub const ACCOUNT_ID_5: AccountId = 5; pub struct TestClusterCreator; impl ClusterCreator for TestClusterCreator { fn create_new_cluster( @@ -168,10 +209,17 @@ pub const TREASURY_ACCOUNT_ID: AccountId = 888; pub const VALIDATOR1_ACCOUNT_ID: AccountId = 111; pub const VALIDATOR2_ACCOUNT_ID: AccountId = 222; pub const VALIDATOR3_ACCOUNT_ID: AccountId = 333; + +pub const VALIDATOR1_SCORE: u64 = 30; +pub const VALIDATOR2_SCORE: u64 = 45; +pub const VALIDATOR3_SCORE: u64 = 25; + pub const PARTIAL_CHARGE: u128 = 100; pub const USER3_BALANCE: u128 = 1000; pub const FREE_CLUSTER_ID: ClusterId = ClusterId::zero(); +pub const ONE_CLUSTER_ID: ClusterId = ClusterId::repeat_byte(5u8); +pub const CERE_CLUSTER_ID: ClusterId = ClusterId::repeat_byte(10u8); pub const PRICING_PARAMS: ClusterPricingParams = ClusterPricingParams { unit_per_mb_streamed: 2_000_000, @@ -180,16 +228,30 @@ pub const PRICING_PARAMS: ClusterPricingParams = ClusterPricingParams { unit_per_get_request: 5_000_000, }; +pub const PRICING_PARAMS_ONE: ClusterPricingParams = ClusterPricingParams { + unit_per_mb_streamed: 10_000_000_000, + unit_per_mb_stored: 10_000_000_000, + unit_per_put_request: 10_000_000_000, + unit_per_get_request: 10_000_000_000, +}; + +pub const PRICING_PARAMS_CERE: ClusterPricingParams = ClusterPricingParams { + unit_per_mb_streamed: DOLLARS, + unit_per_mb_stored: DOLLARS, + unit_per_put_request: DOLLARS, + unit_per_get_request: DOLLARS, +}; + 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; @@ -200,7 +262,7 @@ impl PalletVisitor for TestTreasuryVisitor { } } -fn create_account_id_from_u64(id: u64) -> T::AccountId { +fn create_account_id_from_u128(id: u128) -> T::AccountId { let bytes = id.to_ne_bytes(); T::AccountId::decode(&mut &bytes[..]).unwrap() } @@ -214,9 +276,9 @@ impl SortedListProvider for TestValidator fn iter() -> Box> { Box::new( vec![ - create_account_id_from_u64::(VALIDATOR1_ACCOUNT_ID), - create_account_id_from_u64::(VALIDATOR2_ACCOUNT_ID), - create_account_id_from_u64::(VALIDATOR3_ACCOUNT_ID), + create_account_id_from_u128::(VALIDATOR1_ACCOUNT_ID), + create_account_id_from_u128::(VALIDATOR2_ACCOUNT_ID), + create_account_id_from_u128::(VALIDATOR3_ACCOUNT_ID), ] .into_iter(), ) @@ -236,8 +298,14 @@ impl SortedListProvider for TestValidator // nothing to do on insert. Ok(()) } - fn get_score(_id: &T::AccountId) -> Result { - unimplemented!() + fn get_score(validator_id: &T::AccountId) -> Result { + if *validator_id == create_account_id_from_u128::(VALIDATOR1_ACCOUNT_ID) { + Ok(VALIDATOR1_SCORE) + } else if *validator_id == create_account_id_from_u128::(VALIDATOR2_ACCOUNT_ID) { + Ok(VALIDATOR2_SCORE) + } else { + Ok(VALIDATOR3_SCORE) + } } fn on_update(_: &T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { // nothing to do on update. @@ -269,11 +337,24 @@ impl SortedListProvider for TestValidator } } -pub fn get_fees(cluster_id: &ClusterId) -> Result { - if *cluster_id == FREE_CLUSTER_ID { - Ok(PRICING_FEES_ZERO) +pub fn get_fees(cluster_id: &ClusterId) -> ClusterFeesParams { + if *cluster_id == FREE_CLUSTER_ID || + *cluster_id == ONE_CLUSTER_ID || + *cluster_id == CERE_CLUSTER_ID + { + PRICING_FEES_ZERO + } else { + PRICING_FEES + } +} + +pub fn get_pricing(cluster_id: &ClusterId) -> ClusterPricingParams { + if *cluster_id == FREE_CLUSTER_ID || *cluster_id == ONE_CLUSTER_ID { + PRICING_PARAMS_ONE + } else if *cluster_id == CERE_CLUSTER_ID { + PRICING_PARAMS_CERE } else { - Ok(PRICING_FEES) + PRICING_PARAMS } } @@ -302,13 +383,13 @@ impl ClusterVisitor for TestClusterVisitor { } fn get_pricing_params( - _cluster_id: &ClusterId, + cluster_id: &ClusterId, ) -> Result { - Ok(PRICING_PARAMS) + Ok(get_pricing(cluster_id)) } fn get_fees_params(cluster_id: &ClusterId) -> Result { - get_fees(cluster_id) + Ok(get_fees(cluster_id)) } fn get_reserve_account_id( @@ -334,16 +415,24 @@ impl ExtBuilder { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let _ = pallet_balances::GenesisConfig:: { + let _balance_genesis = pallet_balances::GenesisConfig:: { balances: vec![ - (1, 1000000000000000000000000), + (1, 10000000000000000000000000000), (2, 10), // < PARTIAL_CHARGE (3, USER3_BALANCE), // > PARTIAL_CHARGE (4, 1000000000000000000000000), + (5, 1000000000000000000000000), ], } .assimilate_storage(&mut storage); + let _payout_genesis = pallet_ddc_payouts::GenesisConfig:: { + feeder_account: None, + debtor_customers: Default::default(), + authorised_caller: None, + } + .assimilate_storage(&mut storage); + TestExternalities::new(storage) } pub fn build_and_execute(self, test: impl FnOnce()) { diff --git a/pallets/ddc-payouts/src/tests.rs b/pallets/ddc-payouts/src/tests.rs index 6cd8d2552..2b4c9a1d9 100644 --- a/pallets/ddc-payouts/src/tests.rs +++ b/pallets/ddc-payouts/src/tests.rs @@ -1,7 +1,9 @@ //! Tests for the module. use ddc_primitives::ClusterId; -use frame_support::{assert_noop, assert_ok, error::BadOrigin}; +use frame_support::{assert_noop, assert_ok, error::BadOrigin, traits::Randomness}; +use sp_core::H256; +use sp_runtime::Perquintill; use super::{mock::*, *}; @@ -10,8 +12,8 @@ fn set_authorised_caller_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let root_account = 1u64; - let dac_account = 2u64; + let root_account = 1u128; + let dac_account = 2u128; assert_noop!( DdcPayouts::set_authorised_caller(RuntimeOrigin::signed(root_account), dac_account), @@ -31,8 +33,8 @@ fn set_authorised_caller_works() { #[test] fn begin_billing_report_fails_for_unauthorised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; + let root_account = 1u128; + let dac_account = 2u128; let cluster_id = ClusterId::from([1; 20]); let era = 100; @@ -59,7 +61,7 @@ fn begin_billing_report_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 2u64; + let dac_account = 2u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; @@ -81,7 +83,7 @@ fn begin_billing_report_works() { #[test] fn begin_charging_customers_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let dac_account = 2u64; + let dac_account = 2u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 2; @@ -125,7 +127,7 @@ fn begin_charging_customers_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 2u64; + let dac_account = 2u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 2; @@ -156,10 +158,10 @@ fn begin_charging_customers_works() { #[test] fn send_charging_customers_batch_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; - let user1 = 3u64; - let user2 = 4u64; + let root_account = 1u128; + let dac_account = 2u128; + let user1 = 3u128; + let user2 = 4u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 2; @@ -258,32 +260,34 @@ fn send_charging_customers_batch_fails_uninitialised() { }) } -fn calculate_charge_parts(usage: CustomerUsage) -> CustomerCharge { +fn calculate_charge_parts(cluster_id: ClusterId, usage: CustomerUsage) -> CustomerCharge { + let pricing_params = get_pricing(&cluster_id); + CustomerCharge { - transfer: PRICING_PARAMS.unit_per_mb_streamed * (usage.transferred_bytes as u128) / + transfer: pricing_params.unit_per_mb_streamed * (usage.transferred_bytes as u128) / byte_unit::MEBIBYTE, - storage: (PRICING_PARAMS.unit_per_mb_stored * usage.stored_bytes as u128) / + storage: (pricing_params.unit_per_mb_stored * usage.stored_bytes as u128) / byte_unit::MEBIBYTE, - puts: PRICING_PARAMS.unit_per_put_request * usage.number_of_puts, - gets: PRICING_PARAMS.unit_per_get_request * usage.number_of_gets, + puts: pricing_params.unit_per_put_request * (usage.number_of_puts as u128), + gets: pricing_params.unit_per_get_request * (usage.number_of_gets as u128), } } -fn calculate_charge(usage: CustomerUsage) -> u128 { - let charge = calculate_charge_parts(usage); +fn calculate_charge(cluster_id: ClusterId, usage: CustomerUsage) -> u128 { + let charge = calculate_charge_parts(cluster_id, usage); charge.transfer + charge.storage + charge.puts + charge.gets } #[test] -fn send_charging_customers_batch_works() { +fn send_charging_customers_batch_works1() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 123u64; - let user1 = 1u64; - let user2_debtor = 2u64; - let user3_debtor = 3u64; - let user4 = 4u64; + let dac_account = 123u128; + let user1 = 1u128; + let user2_debtor = 2u128; + let user3_debtor = 3u128; + let user4 = 4u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 3; @@ -344,17 +348,17 @@ fn send_charging_customers_batch_works() { payers1, )); - let usage4_charge = calculate_charge(usage4.clone()); - let mut balance = Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); - assert_eq!(balance, usage4_charge); + let usage4_charge = calculate_charge(cluster_id, usage4.clone()); + let mut balance = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance - Balances::minimum_balance(), usage4_charge); let user2_debt = DdcPayouts::debtor_customers(cluster_id, user2_debtor).unwrap(); - let mut debt = calculate_charge(usage2.clone()); + let mut debt = calculate_charge(cluster_id, usage2.clone()); assert_eq!(user2_debt, debt); let mut report = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - let charge2 = calculate_charge_parts(usage2); - let charge4 = calculate_charge_parts(usage4); + let charge2 = calculate_charge_parts(cluster_id, usage2); + let charge4 = calculate_charge_parts(cluster_id, usage4); assert_eq!(charge2.puts + charge4.puts, report.total_customer_charge.puts); assert_eq!(charge2.gets + charge4.gets, report.total_customer_charge.gets); assert_eq!(charge2.storage + charge4.storage, report.total_customer_charge.storage); @@ -392,7 +396,7 @@ fn send_charging_customers_batch_works() { .into(), ); - assert_eq!(System::events().len(), 5 + 3 + 1); // 3 for Currency::transfer + assert_eq!(System::events().len(), 5 + 1 + 1); // 1 for Currency::transfer // batch 2 let mut before_total_customer_charge = report.total_customer_charge.clone(); @@ -411,13 +415,13 @@ fn send_charging_customers_batch_works() { era, batch_index, customer_id: user1, - amount: calculate_charge(usage1.clone()), + amount: calculate_charge(cluster_id, usage1.clone()), } .into(), ); report = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - let charge1 = calculate_charge_parts(usage1); + let charge1 = calculate_charge_parts(cluster_id, usage1); assert_eq!( charge1.puts + before_total_customer_charge.puts, report.total_customer_charge.puts @@ -439,10 +443,10 @@ fn send_charging_customers_batch_works() { 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::account_id()); // batch 3 - batch_index += 2; + batch_index += 1; before_total_customer_charge = report.total_customer_charge.clone(); assert_ok!(DdcPayouts::send_charging_customers_batch( RuntimeOrigin::signed(dac_account), @@ -452,9 +456,9 @@ fn send_charging_customers_batch_works() { payers3, )); - let user3_charge = calculate_charge(usage3.clone()); - let charge3 = calculate_charge_parts(usage3); - let ratio = Perbill::from_rational(PARTIAL_CHARGE, user3_charge); + let user3_charge = calculate_charge(cluster_id, usage3.clone()); + let charge3 = calculate_charge_parts(cluster_id, usage3); + 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, @@ -473,7 +477,7 @@ fn send_charging_customers_batch_works() { report.total_customer_charge.transfer ); - balance = Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); + balance = Balances::free_balance(DdcPayouts::account_id()); assert_eq!(balance, balance_before + PARTIAL_CHARGE); let user3_debt = DdcPayouts::debtor_customers(cluster_id, user3_debtor).unwrap(); @@ -504,12 +508,83 @@ fn send_charging_customers_batch_works() { }) } +#[test] +fn send_charging_customers_batch_works2() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + + let dac_account = 123u128; + let user5 = 5u128; + let cluster_id = ONE_CLUSTER_ID; + let era = 100; + let max_batch_index = 0; + let batch_index = 0; + let usage5 = CustomerUsage { + // should pass without debt + transferred_bytes: 1024, + stored_bytes: 1024, + number_of_puts: 1, + number_of_gets: 1, + }; + let payers5 = vec![(user5, usage5.clone())]; + + assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); + assert_ok!(DdcPayouts::begin_billing_report( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + + assert_ok!(DdcPayouts::begin_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + max_batch_index, + )); + assert_eq!(System::events().len(), 3); + + // batch 1 + let mut report = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let before_total_customer_charge = report.total_customer_charge.clone(); + let balance_before = Balances::free_balance(DdcPayouts::account_id()); + assert_ok!(DdcPayouts::send_charging_customers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_index, + payers5, + )); + + let usage5_charge = calculate_charge(cluster_id, usage5.clone()); + let charge5 = calculate_charge_parts(cluster_id, usage5); + let balance = Balances::free_balance(DdcPayouts::account_id()); + report = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + assert_eq!(balance, usage5_charge + balance_before); + assert_eq!( + charge5.puts + before_total_customer_charge.puts, + report.total_customer_charge.puts + ); + assert_eq!( + charge5.gets + before_total_customer_charge.gets, + report.total_customer_charge.gets + ); + assert_eq!( + charge5.storage + before_total_customer_charge.storage, + report.total_customer_charge.storage + ); + assert_eq!( + charge5.transfer + before_total_customer_charge.transfer, + report.total_customer_charge.transfer + ); + }) +} + #[test] fn end_charging_customers_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 100u64; - let dac_account = 123u64; - let user1 = 1u64; + let root_account = 100u128; + let dac_account = 123u128; + let user1 = 1u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 2; @@ -580,8 +655,8 @@ fn end_charging_customers_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 123u64; - let user1 = 1u64; + let dac_account = 123u128; + let user1 = 1u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 0; @@ -618,15 +693,15 @@ fn end_charging_customers_works() { )); let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - let charge = calculate_charge(usage1); + let charge = calculate_charge(cluster_id, usage1); System::assert_last_event( Event::Charged { cluster_id, era, batch_index, customer_id: user1, amount: charge } .into(), ); - let mut balance = Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); - assert_eq!(balance, charge); - assert_eq!(System::events().len(), 4 + 3); // 3 for Currency::transfer + let mut balance = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance - Balances::minimum_balance(), charge); + assert_eq!(System::events().len(), 4 + 1); // 1 for Currency::transfer assert_ok!(DdcPayouts::end_charging_customers( RuntimeOrigin::signed(dac_account), @@ -636,9 +711,9 @@ fn end_charging_customers_works() { System::assert_has_event(Event::ChargingFinished { cluster_id, era }.into()); - let treasury_fee = PRICING_FEES.treasury_share * charge; - let reserve_fee = PRICING_FEES.cluster_reserve_share * charge; - let validator_fee = PRICING_FEES.validators_share * charge; + let treasury_fee = get_fees(&cluster_id).treasury_share * charge; + let reserve_fee = get_fees(&cluster_id).cluster_reserve_share * charge; + let validator_fee = get_fees(&cluster_id).validators_share * charge; System::assert_has_event( Event::TreasuryFeesCollected { cluster_id, era, amount: treasury_fee }.into(), @@ -653,30 +728,42 @@ fn end_charging_customers_works() { ); let transfers = 3 + 3 + 3 * 3; // for Currency::transfer - assert_eq!(System::events().len(), 7 + 1 + 3 + transfers); + assert_eq!(System::events().len(), 5 + 1 + 3 + transfers); let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); assert_eq!(report_after.state, State::CustomersChargedWithFees); - let total_left_from_one = (PRICING_FEES.treasury_share + - PRICING_FEES.validators_share + - PRICING_FEES.cluster_reserve_share) + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) .left_from_one(); balance = Balances::free_balance(TREASURY_ACCOUNT_ID); - assert_eq!(balance, PRICING_FEES.treasury_share * charge); + assert_eq!(balance, get_fees(&cluster_id).treasury_share * charge); balance = Balances::free_balance(RESERVE_ACCOUNT_ID); - assert_eq!(balance, PRICING_FEES.cluster_reserve_share * charge); + assert_eq!(balance, get_fees(&cluster_id).cluster_reserve_share * charge); balance = Balances::free_balance(VALIDATOR1_ACCOUNT_ID); - assert_eq!(balance, PRICING_FEES.validators_share * charge / 3); + let mut ratio = Perquintill::from_rational( + VALIDATOR1_SCORE, + VALIDATOR1_SCORE + VALIDATOR2_SCORE + VALIDATOR3_SCORE, + ); + assert_eq!(balance, get_fees(&cluster_id).validators_share * ratio * charge); balance = Balances::free_balance(VALIDATOR2_ACCOUNT_ID); - assert_eq!(balance, PRICING_FEES.validators_share * charge / 3); + ratio = Perquintill::from_rational( + VALIDATOR2_SCORE, + VALIDATOR1_SCORE + VALIDATOR2_SCORE + VALIDATOR3_SCORE, + ); + assert_eq!(balance, get_fees(&cluster_id).validators_share * ratio * charge); balance = Balances::free_balance(VALIDATOR3_ACCOUNT_ID); - assert_eq!(balance, PRICING_FEES.validators_share * charge / 3); + ratio = Perquintill::from_rational( + VALIDATOR3_SCORE, + VALIDATOR1_SCORE + VALIDATOR2_SCORE + VALIDATOR3_SCORE, + ); + assert_eq!(balance, get_fees(&cluster_id).validators_share * ratio * charge); assert_eq!( report_after.total_customer_charge.transfer, @@ -702,8 +789,8 @@ fn end_charging_customers_works_zero_fees() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 123u64; - let user1 = 1u64; + let dac_account = 123u128; + let user1 = 1u128; let cluster_id = ClusterId::zero(); let era = 100; let max_batch_index = 0; @@ -711,8 +798,8 @@ fn end_charging_customers_works_zero_fees() { let usage1 = CustomerUsage { transferred_bytes: 23452345, stored_bytes: 3345234523, - number_of_puts: 4456456345234523, - number_of_gets: 523423, + number_of_puts: 1, + number_of_gets: 1, }; let payers = vec![(user1, usage1.clone())]; @@ -740,15 +827,15 @@ fn end_charging_customers_works_zero_fees() { )); let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - let charge = calculate_charge(usage1); + let charge = calculate_charge(cluster_id, usage1); System::assert_last_event( Event::Charged { cluster_id, era, customer_id: user1, batch_index, amount: charge } .into(), ); - let mut balance = Balances::free_balance(DdcPayouts::sub_account_id(cluster_id, era)); - assert_eq!(balance, charge); - assert_eq!(System::events().len(), 4 + 3); // 3 for Currency::transfer + let mut balance = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance - Balances::minimum_balance(), charge); + assert_eq!(System::events().len(), 4 + 1); // 1 for Currency::transfer assert_ok!(DdcPayouts::end_charging_customers( RuntimeOrigin::signed(dac_account), @@ -757,22 +844,22 @@ fn end_charging_customers_works_zero_fees() { )); System::assert_has_event(Event::ChargingFinished { cluster_id, era }.into()); - assert_eq!(System::events().len(), 7 + 1); + assert_eq!(System::events().len(), 5 + 1); let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); assert_eq!(report_after.state, State::CustomersChargedWithFees); - let fees = get_fees(&cluster_id).unwrap(); + let fees = get_fees(&cluster_id); let total_left_from_one = (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); @@ -811,9 +898,9 @@ fn end_charging_customers_works_zero_fees() { #[test] fn begin_rewarding_providers_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; - let user1 = 3u64; + let root_account = 1u128; + let dac_account = 2u128; + let user1 = 3u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 2; @@ -936,8 +1023,8 @@ fn begin_rewarding_providers_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 123u64; - let user1 = 1u64; + let dac_account = 123u128; + let user1 = 1u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 0; @@ -995,11 +1082,11 @@ fn begin_rewarding_providers_works() { #[test] fn send_rewarding_providers_batch_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; - let user1 = 3u64; - let user2 = 4u64; - let node1 = 33u64; + let root_account = 1u128; + let dac_account = 2u128; + let user1 = 3u128; + let user2 = 4u128; + let node1 = 33u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 1; @@ -1140,11 +1227,11 @@ fn send_rewarding_providers_batch_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 123u64; - let user1 = 1u64; - let node1 = 10u64; - let node2 = 11u64; - let node3 = 12u64; + let dac_account = 123u128; + let user1 = 1u128; + let node1 = 10u128; + let node2 = 11u128; + let node3 = 12u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 0; @@ -1232,9 +1319,9 @@ fn send_rewarding_providers_batch_works() { )); let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); - let total_left_from_one = (PRICING_FEES.treasury_share + - PRICING_FEES.validators_share + - PRICING_FEES.cluster_reserve_share) + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) .left_from_one(); assert_eq!( @@ -1270,46 +1357,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, @@ -1318,25 +1418,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; - ratio = Perbill::from_rational(node_usage3.stored_bytes, total_nodes_usage.stored_bytes); - storage_charge = ratio * 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.number_of_puts, total_nodes_usage.number_of_puts); - puts_charge = ratio * report_after.total_customer_charge.puts; + 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; + + 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), @@ -1346,14 +1463,1020 @@ fn send_rewarding_providers_batch_works() { }) } +#[test] +fn send_rewarding_providers_batch_100_nodes_small_usage_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + + let num_nodes = 100; + let num_users = 5; + let dac_account = 123u128; + let bank = 1u128; + let cluster_id = ONE_CLUSTER_ID; + let era = 100; + let user_batch_size = 10; + let node_batch_size = 10; + let mut batch_user_index = 0; + let mut batch_node_index = 0; + let usage1 = CustomerUsage { + transferred_bytes: 1024, + stored_bytes: 1024, + number_of_puts: 1, + number_of_gets: 1, + }; + + let node_usage1 = NodeUsage { + // CDN + transferred_bytes: Perquintill::from_float(0.75) * usage1.transferred_bytes, + stored_bytes: 0, + number_of_puts: Perquintill::from_float(0.75) * usage1.number_of_puts, + number_of_gets: Perquintill::from_float(0.75) * usage1.number_of_gets, + }; + + let node_usage2 = NodeUsage { + // Storage + transferred_bytes: 0, + stored_bytes: usage1.stored_bytes * 2, + number_of_puts: 0, + number_of_gets: 0, + }; + + let node_usage3 = NodeUsage { + // CDN + Storage + transferred_bytes: usage1.transferred_bytes * 2, + stored_bytes: usage1.stored_bytes * 3, + number_of_puts: usage1.number_of_puts * 2, + number_of_gets: usage1.number_of_gets * 2, + }; + + let mut payees: Vec> = Vec::new(); + let mut node_batch: Vec<(u128, NodeUsage)> = Vec::new(); + let mut total_nodes_usage = NodeUsage::default(); + for i in 10..10 + num_nodes { + let node_usage = match i % 3 { + 0 => node_usage1.clone(), + 1 => node_usage2.clone(), + 2 => node_usage3.clone(), + _ => unreachable!(), + }; + total_nodes_usage.transferred_bytes += node_usage.transferred_bytes; + total_nodes_usage.stored_bytes += node_usage.stored_bytes; + total_nodes_usage.number_of_puts += node_usage.number_of_puts; + total_nodes_usage.number_of_gets += node_usage.number_of_gets; + + node_batch.push((i, node_usage)); + if node_batch.len() == node_batch_size { + payees.push(node_batch.clone()); + node_batch.clear(); + } + } + if !node_batch.is_empty() { + payees.push(node_batch.clone()); + } + + let mut total_charge = 0u128; + let mut payers: Vec> = Vec::new(); + let mut user_batch: Vec<(u128, CustomerUsage)> = Vec::new(); + for user_id in 1000..1000 + num_users { + let ratio = match user_id % 5 { + 0 => Perquintill::one(), + 1 => Perquintill::from_float(0.5), + 2 => Perquintill::from_float(2f64), + 3 => Perquintill::from_float(0.25), + 4 => Perquintill::from_float(0.001), + _ => unreachable!(), + }; + + let mut user_usage = usage1.clone(); + user_usage.transferred_bytes = ratio * user_usage.transferred_bytes; + user_usage.stored_bytes = ratio * user_usage.stored_bytes; + user_usage.number_of_puts = ratio * user_usage.number_of_puts; + user_usage.number_of_gets = ratio * user_usage.number_of_gets; + + let expected_charge = calculate_charge(cluster_id, user_usage.clone()); + Balances::transfer( + RuntimeOrigin::signed(bank), + user_id, + (expected_charge * 2).max(Balances::minimum_balance()), + ) + .unwrap(); + total_charge += expected_charge; + + user_batch.push((user_id, user_usage)); + if user_batch.len() == user_batch_size { + payers.push(user_batch.clone()); + user_batch.clear(); + } + } + if !user_batch.is_empty() { + payers.push(user_batch.clone()); + } + + assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); + assert_ok!(DdcPayouts::begin_billing_report( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + assert_ok!(DdcPayouts::begin_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payers.len() - 1) as u16, + )); + + for batch in payers.iter() { + assert_ok!(DdcPayouts::send_charging_customers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_user_index, + batch.to_vec(), + )); + + for (customer_id, usage) in batch.iter() { + let charge = calculate_charge(cluster_id, usage.clone()); + + System::assert_has_event( + Event::Charged { + cluster_id, + era, + customer_id: *customer_id, + batch_index: batch_user_index, + amount: charge, + } + .into(), + ); + } + batch_user_index += 1; + } + + let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let balance1 = Balances::free_balance(report_before.vault); + let balance2 = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance1, balance2); + assert_eq!(report_before.vault, DdcPayouts::account_id()); + assert_eq!(balance1 - Balances::minimum_balance(), total_charge); + + assert_ok!(DdcPayouts::end_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + + let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) + .left_from_one(); + + let total_charge = report_after.total_customer_charge.transfer + + report_before.total_customer_charge.storage + + report_before.total_customer_charge.puts + + report_before.total_customer_charge.gets; + let balance_after = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(total_charge, balance_after - Balances::minimum_balance()); + + assert_eq!( + report_after.total_customer_charge.transfer, + total_left_from_one * report_before.total_customer_charge.transfer + ); + assert_eq!( + report_after.total_customer_charge.storage, + total_left_from_one * report_before.total_customer_charge.storage + ); + assert_eq!( + report_after.total_customer_charge.puts, + total_left_from_one * report_before.total_customer_charge.puts + ); + assert_eq!( + report_after.total_customer_charge.gets, + total_left_from_one * report_before.total_customer_charge.gets + ); + + assert_ok!(DdcPayouts::begin_rewarding_providers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payees.len() - 1) as u16, + total_nodes_usage.clone(), + )); + + for batch in payees.iter() { + let before_batch = Balances::free_balance(DdcPayouts::account_id()); + assert_ok!(DdcPayouts::send_rewarding_providers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_node_index, + batch.to_vec(), + )); + + let mut batch_charge = 0; + for (node1, node_usage1) in batch.iter() { + let ratio1_transfer = Perquintill::from_rational( + node_usage1.transferred_bytes, + total_nodes_usage.transferred_bytes, + ); + let transfer_charge = ratio1_transfer * report_after.total_customer_charge.transfer; + + let ratio1_storage = Perquintill::from_rational( + node_usage1.stored_bytes, + total_nodes_usage.stored_bytes, + ); + let storage_charge = ratio1_storage * report_after.total_customer_charge.storage; + + let ratio1_puts = Perquintill::from_rational( + node_usage1.number_of_puts, + total_nodes_usage.number_of_puts, + ); + let puts_charge = ratio1_puts * report_after.total_customer_charge.puts; + + let ratio1_gets = Perquintill::from_rational( + node_usage1.number_of_gets, + total_nodes_usage.number_of_gets, + ); + let gets_charge = ratio1_gets * report_after.total_customer_charge.gets; + + let balance_node1 = Balances::free_balance(node1); + assert!( + (transfer_charge + storage_charge + puts_charge + gets_charge) - balance_node1 < + MAX_DUST.into() + ); + + batch_charge += transfer_charge + storage_charge + puts_charge + gets_charge; + } + let after_batch = Balances::free_balance(DdcPayouts::account_id()); + assert!(batch_charge + after_batch - before_batch < MAX_DUST.into()); + + batch_node_index += 1; + } + assert!(Balances::free_balance(DdcPayouts::account_id()) < MAX_DUST.into()); + }) +} + +#[test] +fn send_rewarding_providers_batch_100_nodes_large_usage_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + + let num_nodes = 100; + let num_users = 5; + let dac_account = 123u128; + let bank = 1u128; + let cluster_id = ONE_CLUSTER_ID; + let era = 100; + let user_batch_size = 10; + let node_batch_size = 10; + let mut batch_user_index = 0; + let mut batch_node_index = 0; + let usage1 = CustomerUsage { + transferred_bytes: 1024, + stored_bytes: 1024, + number_of_puts: 1, + number_of_gets: 1, + }; + + let node_usage1 = NodeUsage { + // CDN + transferred_bytes: Perquintill::from_float(0.75) * usage1.transferred_bytes, + stored_bytes: 0, + number_of_puts: Perquintill::from_float(0.75) * usage1.number_of_puts, + number_of_gets: Perquintill::from_float(0.75) * usage1.number_of_gets, + }; + + let node_usage2 = NodeUsage { + // Storage + transferred_bytes: 0, + stored_bytes: usage1.stored_bytes * 2, + number_of_puts: 0, + number_of_gets: 0, + }; + + let node_usage3 = NodeUsage { + // CDN + Storage + transferred_bytes: usage1.transferred_bytes * 2, + stored_bytes: usage1.stored_bytes * 3, + number_of_puts: usage1.number_of_puts * 2, + number_of_gets: usage1.number_of_gets * 2, + }; + + let mut payees: Vec> = Vec::new(); + let mut node_batch: Vec<(u128, NodeUsage)> = Vec::new(); + let mut total_nodes_usage = NodeUsage::default(); + for i in 10..10 + num_nodes { + let ratio = match i % 5 { + 0 => Perquintill::from_float(1_000_000.0), + 1 => Perquintill::from_float(10_000_000.0), + 2 => Perquintill::from_float(100_000_000.0), + 3 => Perquintill::from_float(1_000_000_000.0), + 4 => Perquintill::from_float(10_000_000_000.0), + _ => unreachable!(), + }; + let mut node_usage = match i % 3 { + 0 => node_usage1.clone(), + 1 => node_usage2.clone(), + 2 => node_usage3.clone(), + _ => unreachable!(), + }; + node_usage.transferred_bytes = ratio * node_usage.transferred_bytes; + node_usage.stored_bytes = ratio * node_usage.stored_bytes; + node_usage.number_of_puts = ratio * node_usage.number_of_puts; + node_usage.number_of_gets = ratio * node_usage.number_of_gets; + + total_nodes_usage.transferred_bytes += node_usage.transferred_bytes; + total_nodes_usage.stored_bytes += node_usage.stored_bytes; + total_nodes_usage.number_of_puts += node_usage.number_of_puts; + total_nodes_usage.number_of_gets += node_usage.number_of_gets; + + node_batch.push((i, node_usage)); + if node_batch.len() == node_batch_size { + payees.push(node_batch.clone()); + node_batch.clear(); + } + } + if !node_batch.is_empty() { + payees.push(node_batch.clone()); + } + + let mut total_charge = 0u128; + let mut payers: Vec> = Vec::new(); + let mut user_batch: Vec<(u128, CustomerUsage)> = Vec::new(); + for user_id in 1000..1000 + num_users { + let ratio = match user_id % 5 { + 0 => Perquintill::from_float(1_000_000.0), + 1 => Perquintill::from_float(10_000_000.0), + 2 => Perquintill::from_float(100_000_000.0), + 3 => Perquintill::from_float(1_000_000_000.0), + 4 => Perquintill::from_float(10_000_000_000.0), + _ => unreachable!(), + }; + + let mut user_usage = usage1.clone(); + user_usage.transferred_bytes = ratio * user_usage.transferred_bytes; + user_usage.stored_bytes = ratio * user_usage.stored_bytes; + user_usage.number_of_puts = ratio * user_usage.number_of_puts; + user_usage.number_of_gets = ratio * user_usage.number_of_gets; + + let expected_charge = calculate_charge(cluster_id, user_usage.clone()); + Balances::transfer( + RuntimeOrigin::signed(bank), + user_id, + (expected_charge * 2).max(Balances::minimum_balance()), + ) + .unwrap(); + total_charge += expected_charge; + + user_batch.push((user_id, user_usage)); + if user_batch.len() == user_batch_size { + payers.push(user_batch.clone()); + user_batch.clear(); + } + } + if !user_batch.is_empty() { + payers.push(user_batch.clone()); + } + + assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); + assert_ok!(DdcPayouts::begin_billing_report( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + assert_ok!(DdcPayouts::begin_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payers.len() - 1) as u16, + )); + + for batch in payers.iter() { + assert_ok!(DdcPayouts::send_charging_customers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_user_index, + batch.to_vec(), + )); + + for (customer_id, usage) in batch.iter() { + let charge = calculate_charge(cluster_id, usage.clone()); + + System::assert_has_event( + Event::Charged { + cluster_id, + era, + customer_id: *customer_id, + batch_index: batch_user_index, + amount: charge, + } + .into(), + ); + } + batch_user_index += 1; + } + + let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let balance1 = Balances::free_balance(report_before.vault); + let balance2 = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance1, balance2); + assert_eq!(report_before.vault, DdcPayouts::account_id()); + assert_eq!(balance1 - Balances::minimum_balance(), total_charge); + + assert_ok!(DdcPayouts::end_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + + let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) + .left_from_one(); + + let total_charge = report_after.total_customer_charge.transfer + + report_before.total_customer_charge.storage + + report_before.total_customer_charge.puts + + report_before.total_customer_charge.gets; + let balance_after = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(total_charge, balance_after - Balances::minimum_balance()); + + assert_eq!( + report_after.total_customer_charge.transfer, + total_left_from_one * report_before.total_customer_charge.transfer + ); + assert_eq!( + report_after.total_customer_charge.storage, + total_left_from_one * report_before.total_customer_charge.storage + ); + assert_eq!( + report_after.total_customer_charge.puts, + total_left_from_one * report_before.total_customer_charge.puts + ); + assert_eq!( + report_after.total_customer_charge.gets, + total_left_from_one * report_before.total_customer_charge.gets + ); + + assert_ok!(DdcPayouts::begin_rewarding_providers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payees.len() - 1) as u16, + total_nodes_usage.clone(), + )); + + for batch in payees.iter() { + let before_batch = Balances::free_balance(DdcPayouts::account_id()); + assert_ok!(DdcPayouts::send_rewarding_providers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_node_index, + batch.to_vec(), + )); + + let mut batch_charge = 0; + for (node1, node_usage1) in batch.iter() { + let ratio1_transfer = Perquintill::from_rational( + node_usage1.transferred_bytes, + total_nodes_usage.transferred_bytes, + ); + let transfer_charge = ratio1_transfer * report_after.total_customer_charge.transfer; + + let ratio1_storage = Perquintill::from_rational( + node_usage1.stored_bytes, + total_nodes_usage.stored_bytes, + ); + let storage_charge = ratio1_storage * report_after.total_customer_charge.storage; + + let ratio1_puts = Perquintill::from_rational( + node_usage1.number_of_puts, + total_nodes_usage.number_of_puts, + ); + let puts_charge = ratio1_puts * report_after.total_customer_charge.puts; + + let ratio1_gets = Perquintill::from_rational( + node_usage1.number_of_gets, + total_nodes_usage.number_of_gets, + ); + let gets_charge = ratio1_gets * report_after.total_customer_charge.gets; + + let balance_node1 = Balances::free_balance(node1); + assert!( + (transfer_charge + storage_charge + puts_charge + gets_charge) - balance_node1 < + MAX_DUST.into() + ); + + batch_charge += transfer_charge + storage_charge + puts_charge + gets_charge; + } + let after_batch = Balances::free_balance(DdcPayouts::account_id()); + assert!(batch_charge + after_batch - before_batch < MAX_DUST.into()); + + batch_node_index += 1; + } + assert!(Balances::free_balance(DdcPayouts::account_id()) < MAX_DUST.into()); + }) +} + +#[test] +fn send_rewarding_providers_batch_100_nodes_small_large_usage_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + + let num_nodes = 100; + let num_users = 5; + let dac_account = 123u128; + let bank = 1u128; + let cluster_id = ONE_CLUSTER_ID; + let era = 100; + let user_batch_size = 10; + let node_batch_size = 10; + let mut batch_user_index = 0; + let mut batch_node_index = 0; + let usage1 = CustomerUsage { + transferred_bytes: 1024, + stored_bytes: 1024, + number_of_puts: 1, + number_of_gets: 1, + }; + + let node_usage1 = NodeUsage { + // CDN + transferred_bytes: Perquintill::from_float(0.75) * usage1.transferred_bytes, + stored_bytes: 0, + number_of_puts: Perquintill::from_float(0.75) * usage1.number_of_puts, + number_of_gets: Perquintill::from_float(0.75) * usage1.number_of_gets, + }; + + let node_usage2 = NodeUsage { + // Storage + transferred_bytes: 0, + stored_bytes: usage1.stored_bytes * 2, + number_of_puts: 0, + number_of_gets: 0, + }; + + let node_usage3 = NodeUsage { + // CDN + Storage + transferred_bytes: usage1.transferred_bytes * 2, + stored_bytes: usage1.stored_bytes * 3, + number_of_puts: usage1.number_of_puts * 2, + number_of_gets: usage1.number_of_gets * 2, + }; + + let mut payees: Vec> = Vec::new(); + let mut node_batch: Vec<(u128, NodeUsage)> = Vec::new(); + let mut total_nodes_usage = NodeUsage::default(); + for i in 10..10 + num_nodes { + let ratio = match i % 5 { + 0 => Perquintill::from_float(1_000_000.0), + 1 => Perquintill::from_float(0.5), + 2 => Perquintill::from_float(100_000_000.0), + 3 => Perquintill::from_float(0.25), + 4 => Perquintill::from_float(10_000_000_000.0), + _ => unreachable!(), + }; + let mut node_usage = match i % 3 { + 0 => node_usage1.clone(), + 1 => node_usage2.clone(), + 2 => node_usage3.clone(), + _ => unreachable!(), + }; + node_usage.transferred_bytes = ratio * node_usage.transferred_bytes; + node_usage.stored_bytes = ratio * node_usage.stored_bytes; + node_usage.number_of_puts = ratio * node_usage.number_of_puts; + node_usage.number_of_gets = ratio * node_usage.number_of_gets; + + total_nodes_usage.transferred_bytes += node_usage.transferred_bytes; + total_nodes_usage.stored_bytes += node_usage.stored_bytes; + total_nodes_usage.number_of_puts += node_usage.number_of_puts; + total_nodes_usage.number_of_gets += node_usage.number_of_gets; + + node_batch.push((i, node_usage)); + if node_batch.len() == node_batch_size { + payees.push(node_batch.clone()); + node_batch.clear(); + } + } + if !node_batch.is_empty() { + payees.push(node_batch.clone()); + } + + let mut total_charge = 0u128; + let mut payers: Vec> = Vec::new(); + let mut user_batch: Vec<(u128, CustomerUsage)> = Vec::new(); + for user_id in 1000..1000 + num_users { + let ratio = match user_id % 5 { + 0 => Perquintill::from_float(1_000_000.0), + 1 => Perquintill::from_float(10_000_000.0), + 2 => Perquintill::from_float(100_000_000.0), + 3 => Perquintill::from_float(1_000_000_000.0), + 4 => Perquintill::from_float(10_000_000_000.0), + _ => unreachable!(), + }; + + let mut user_usage = usage1.clone(); + user_usage.transferred_bytes = ratio * user_usage.transferred_bytes; + user_usage.stored_bytes = ratio * user_usage.stored_bytes; + user_usage.number_of_puts = ratio * user_usage.number_of_puts; + user_usage.number_of_gets = ratio * user_usage.number_of_gets; + + let expected_charge = calculate_charge(cluster_id, user_usage.clone()); + Balances::transfer( + RuntimeOrigin::signed(bank), + user_id, + (expected_charge * 2).max(Balances::minimum_balance()), + ) + .unwrap(); + total_charge += expected_charge; + + user_batch.push((user_id, user_usage)); + if user_batch.len() == user_batch_size { + payers.push(user_batch.clone()); + user_batch.clear(); + } + } + if !user_batch.is_empty() { + payers.push(user_batch.clone()); + } + + assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); + assert_ok!(DdcPayouts::begin_billing_report( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + assert_ok!(DdcPayouts::begin_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payers.len() - 1) as u16, + )); + + for batch in payers.iter() { + assert_ok!(DdcPayouts::send_charging_customers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_user_index, + batch.to_vec(), + )); + + for (customer_id, usage) in batch.iter() { + let charge = calculate_charge(cluster_id, usage.clone()); + + System::assert_has_event( + Event::Charged { + cluster_id, + era, + customer_id: *customer_id, + batch_index: batch_user_index, + amount: charge, + } + .into(), + ); + } + batch_user_index += 1; + } + + let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let balance1 = Balances::free_balance(report_before.vault); + let balance2 = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance1, balance2); + assert_eq!(report_before.vault, DdcPayouts::account_id()); + assert_eq!(balance1 - Balances::minimum_balance(), total_charge); + + assert_ok!(DdcPayouts::end_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + + let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) + .left_from_one(); + + let total_charge = report_after.total_customer_charge.transfer + + report_before.total_customer_charge.storage + + report_before.total_customer_charge.puts + + report_before.total_customer_charge.gets; + let balance_after = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(total_charge, balance_after - Balances::minimum_balance()); + + assert_eq!( + report_after.total_customer_charge.transfer, + total_left_from_one * report_before.total_customer_charge.transfer + ); + assert_eq!( + report_after.total_customer_charge.storage, + total_left_from_one * report_before.total_customer_charge.storage + ); + assert_eq!( + report_after.total_customer_charge.puts, + total_left_from_one * report_before.total_customer_charge.puts + ); + assert_eq!( + report_after.total_customer_charge.gets, + total_left_from_one * report_before.total_customer_charge.gets + ); + + assert_ok!(DdcPayouts::begin_rewarding_providers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payees.len() - 1) as u16, + total_nodes_usage.clone(), + )); + + for batch in payees.iter() { + let before_batch = Balances::free_balance(DdcPayouts::account_id()); + assert_ok!(DdcPayouts::send_rewarding_providers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_node_index, + batch.to_vec(), + )); + + let mut batch_charge = 0; + for (node1, node_usage1) in batch.iter() { + let ratio1_transfer = Perquintill::from_rational( + node_usage1.transferred_bytes, + total_nodes_usage.transferred_bytes, + ); + let transfer_charge = ratio1_transfer * report_after.total_customer_charge.transfer; + + let ratio1_storage = Perquintill::from_rational( + node_usage1.stored_bytes, + total_nodes_usage.stored_bytes, + ); + let storage_charge = ratio1_storage * report_after.total_customer_charge.storage; + + let ratio1_puts = Perquintill::from_rational( + node_usage1.number_of_puts, + total_nodes_usage.number_of_puts, + ); + let puts_charge = ratio1_puts * report_after.total_customer_charge.puts; + + let ratio1_gets = Perquintill::from_rational( + node_usage1.number_of_gets, + total_nodes_usage.number_of_gets, + ); + let gets_charge = ratio1_gets * report_after.total_customer_charge.gets; + + let balance_node1 = Balances::free_balance(node1); + assert!( + (transfer_charge + storage_charge + puts_charge + gets_charge) - balance_node1 < + MAX_DUST.into() + ); + + batch_charge += transfer_charge + storage_charge + puts_charge + gets_charge; + } + let after_batch = Balances::free_balance(DdcPayouts::account_id()); + assert!(batch_charge + after_batch - before_batch < MAX_DUST.into()); + + batch_node_index += 1; + } + assert!(Balances::free_balance(DdcPayouts::account_id()) < MAX_DUST.into()); + }) +} + +fn generate_random_u64>(_: &T, min: u64, max: u64) -> u64 { + let (random_seed, _) = T::random_seed(); + let random_raw = u64::from_be_bytes(random_seed.as_bytes()[0..8].try_into().unwrap()); + + min.saturating_add(random_raw % (max.saturating_sub(min).saturating_add(1))) +} + +#[test] +fn send_rewarding_providers_batch_100_nodes_random_usage_works() { + ExtBuilder.build_and_execute(|| { + System::set_block_number(1); + + let mock_randomness = MockRandomness::default(); + let min: u64 = 1024; + let max: u64 = 1024 * 1024; + let num_nodes = 100; + let num_users = 100; + let dac_account = 123u128; + let bank = 1u128; + let cluster_id = CERE_CLUSTER_ID; + let era = 100; + let user_batch_size = 10; + let node_batch_size = 10; + let mut batch_user_index = 0; + let mut batch_node_index = 0; + let mut payees: Vec> = Vec::new(); + let mut node_batch: Vec<(u128, NodeUsage)> = Vec::new(); + let mut total_nodes_usage = NodeUsage::default(); + for i in 10..10 + num_nodes { + let node_usage = NodeUsage { + transferred_bytes: generate_random_u64(&mock_randomness, min, max), + stored_bytes: generate_random_u64(&mock_randomness, min, max), + number_of_puts: generate_random_u64(&mock_randomness, min, max), + number_of_gets: generate_random_u64(&mock_randomness, min, max), + }; + + total_nodes_usage.transferred_bytes += node_usage.transferred_bytes; + total_nodes_usage.stored_bytes += node_usage.stored_bytes; + total_nodes_usage.number_of_puts += node_usage.number_of_puts; + total_nodes_usage.number_of_gets += node_usage.number_of_gets; + + node_batch.push((i, node_usage)); + if node_batch.len() == node_batch_size { + payees.push(node_batch.clone()); + node_batch.clear(); + } + } + if !node_batch.is_empty() { + payees.push(node_batch.clone()); + } + + let mut total_charge = 0u128; + let mut payers: Vec> = Vec::new(); + let mut user_batch: Vec<(u128, CustomerUsage)> = Vec::new(); + for user_id in 1000..1000 + num_users { + let user_usage = CustomerUsage { + transferred_bytes: generate_random_u64(&mock_randomness, min, max), + stored_bytes: generate_random_u64(&mock_randomness, min, max), + number_of_puts: generate_random_u64(&mock_randomness, min, max), + number_of_gets: generate_random_u64(&mock_randomness, min, max), + }; + + let expected_charge = calculate_charge(cluster_id, user_usage.clone()); + Balances::transfer( + RuntimeOrigin::signed(bank), + user_id, + (expected_charge * 2).max(Balances::minimum_balance()), + ) + .unwrap(); + total_charge += expected_charge; + + user_batch.push((user_id, user_usage)); + if user_batch.len() == user_batch_size { + payers.push(user_batch.clone()); + user_batch.clear(); + } + } + if !user_batch.is_empty() { + payers.push(user_batch.clone()); + } + + assert_ok!(DdcPayouts::set_authorised_caller(RuntimeOrigin::root(), dac_account)); + assert_ok!(DdcPayouts::begin_billing_report( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + assert_ok!(DdcPayouts::begin_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payers.len() - 1) as u16, + )); + + for batch in payers.iter() { + assert_ok!(DdcPayouts::send_charging_customers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_user_index, + batch.to_vec(), + )); + + for (customer_id, usage) in batch.iter() { + let charge = calculate_charge(cluster_id, usage.clone()); + + System::assert_has_event( + Event::Charged { + cluster_id, + era, + customer_id: *customer_id, + batch_index: batch_user_index, + amount: charge, + } + .into(), + ); + } + batch_user_index += 1; + } + + let report_before = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let balance1 = Balances::free_balance(report_before.vault); + let balance2 = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(balance1, balance2); + assert_eq!(report_before.vault, DdcPayouts::account_id()); + assert_eq!(balance1 - Balances::minimum_balance(), total_charge); + + assert_ok!(DdcPayouts::end_charging_customers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + )); + + let report_after = DdcPayouts::active_billing_reports(cluster_id, era).unwrap(); + let total_left_from_one = (get_fees(&cluster_id).treasury_share + + get_fees(&cluster_id).validators_share + + get_fees(&cluster_id).cluster_reserve_share) + .left_from_one(); + + let total_charge = report_after.total_customer_charge.transfer + + report_before.total_customer_charge.storage + + report_before.total_customer_charge.puts + + report_before.total_customer_charge.gets; + let balance_after = Balances::free_balance(DdcPayouts::account_id()); + assert_eq!(total_charge, balance_after - Balances::minimum_balance()); + + assert_eq!( + report_after.total_customer_charge.transfer, + total_left_from_one * report_before.total_customer_charge.transfer + ); + assert_eq!( + report_after.total_customer_charge.storage, + total_left_from_one * report_before.total_customer_charge.storage + ); + assert_eq!( + report_after.total_customer_charge.puts, + total_left_from_one * report_before.total_customer_charge.puts + ); + assert_eq!( + report_after.total_customer_charge.gets, + total_left_from_one * report_before.total_customer_charge.gets + ); + + assert_ok!(DdcPayouts::begin_rewarding_providers( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + (payees.len() - 1) as u16, + total_nodes_usage.clone(), + )); + + for batch in payees.iter() { + let before_batch = Balances::free_balance(DdcPayouts::account_id()); + assert_ok!(DdcPayouts::send_rewarding_providers_batch( + RuntimeOrigin::signed(dac_account), + cluster_id, + era, + batch_node_index, + batch.to_vec(), + )); + + let mut batch_charge = 0; + for (node1, node_usage1) in batch.iter() { + let ratio1_transfer = Perquintill::from_rational( + node_usage1.transferred_bytes, + total_nodes_usage.transferred_bytes, + ); + let transfer_charge = ratio1_transfer * report_after.total_customer_charge.transfer; + + let ratio1_storage = Perquintill::from_rational( + node_usage1.stored_bytes, + total_nodes_usage.stored_bytes, + ); + let storage_charge = ratio1_storage * report_after.total_customer_charge.storage; + + let ratio1_puts = Perquintill::from_rational( + node_usage1.number_of_puts, + total_nodes_usage.number_of_puts, + ); + let puts_charge = ratio1_puts * report_after.total_customer_charge.puts; + + let ratio1_gets = Perquintill::from_rational( + node_usage1.number_of_gets, + total_nodes_usage.number_of_gets, + ); + let gets_charge = ratio1_gets * report_after.total_customer_charge.gets; + + let balance_node1 = Balances::free_balance(node1); + assert!( + (transfer_charge + storage_charge + puts_charge + gets_charge) - balance_node1 < + MAX_DUST.into() + ); + + batch_charge += transfer_charge + storage_charge + puts_charge + gets_charge; + } + let after_batch = Balances::free_balance(DdcPayouts::account_id()); + assert!(batch_charge + after_batch - before_batch < MAX_DUST.into()); + + batch_node_index += 1; + } + assert!(Balances::free_balance(DdcPayouts::account_id()) < MAX_DUST.into()); + }) +} + #[test] fn end_rewarding_providers_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; - let user1 = 3u64; - let user2 = 4u64; - let node1 = 33u64; + let root_account = 1u128; + let dac_account = 2u128; + let user1 = 3u128; + let user2 = 4u128; + let node1 = 33u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 1; @@ -1509,16 +2632,30 @@ fn end_rewarding_providers_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 2u64; - let user1 = 3u64; - let node1 = 33u64; + let dac_account = 2u128; + 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)); @@ -1584,11 +2721,11 @@ fn end_rewarding_providers_works() { #[test] fn end_billing_report_fails_uninitialised() { ExtBuilder.build_and_execute(|| { - let root_account = 1u64; - let dac_account = 2u64; - let user1 = 3u64; - let user2 = 4u64; - let node1 = 33u64; + let root_account = 1u128; + let dac_account = 2u128; + let user1 = 3u128; + let user2 = 4u128; + let node1 = 33u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 1; @@ -1721,9 +2858,9 @@ fn end_billing_report_works() { ExtBuilder.build_and_execute(|| { System::set_block_number(1); - let dac_account = 2u64; - let user1 = 3u64; - let node1 = 33u64; + let dac_account = 2u128; + let user1 = 3u128; + let node1 = 33u128; let cluster_id = ClusterId::from([12; 20]); let era = 100; let max_batch_index = 0; diff --git a/pallets/ddc-payouts/src/weights.rs b/pallets/ddc-payouts/src/weights.rs index 5f0578c31..a8ba246c7 100644 --- a/pallets/ddc-payouts/src/weights.rs +++ b/pallets/ddc-payouts/src/weights.rs @@ -1,9 +1,9 @@ //! Autogenerated weights for pallet_ddc_payouts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Yahors-MacBook-Pro.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2023-12-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bench`, CPU: `DO-Premium-AMD` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Interpreted, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/release/cere @@ -43,20 +43,20 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: DdcPayouts AuthorisedCaller (r:0 w:1) fn set_authorised_caller() -> Weight { - Weight::from_ref_time(11_000_000_u64) + Weight::from_ref_time(90_258_000_u64) .saturating_add(T::DbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_billing_report() -> Weight { - Weight::from_ref_time(19_000_000_u64) + Weight::from_ref_time(214_646_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_charging_customers() -> Weight { - Weight::from_ref_time(19_000_000_u64) + Weight::from_ref_time(228_676_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -68,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: DdcPayouts DebtorCustomers (r:1 w:1) /// The range of component `b` is `[1, 1000]`. fn send_charging_customers_batch(b: u32, ) -> Weight { - Weight::from_ref_time(12_333_820_u64) - // Standard Error: 298_759 - .saturating_add(Weight::from_ref_time(24_367_120_u64).saturating_mul(b as u64)) + Weight::from_ref_time(891_324_000_u64) + // Standard Error: 3_864_375 + .saturating_add(Weight::from_ref_time(558_679_506_u64).saturating_mul(b as u64)) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(b as u64))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -81,17 +81,19 @@ impl WeightInfo for SubstrateWeight { // Storage: DdcClusters ClustersGovParams (r:1 w:0) // Storage: System Account (r:3 w:3) // Storage: DdcClusters Clusters (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:2 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) fn end_charging_customers() -> Weight { - Weight::from_ref_time(89_000_000_u64) - .saturating_add(T::DbWeight::get().reads(10_u64)) + Weight::from_ref_time(1_691_550_000_u64) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_rewarding_providers() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(234_686_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -100,25 +102,25 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:2 w:2) /// The range of component `b` is `[1, 1000]`. fn send_rewarding_providers_batch(b: u32, ) -> Weight { - Weight::from_ref_time(32_000_000_u64) - // Standard Error: 5_087 - .saturating_add(Weight::from_ref_time(14_402_776_u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + Weight::from_ref_time(565_710_000_u64) + // Standard Error: 854_032 + .saturating_add(Weight::from_ref_time(408_429_599_u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(b as u64))) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn end_rewarding_providers() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(274_535_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn end_billing_report() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(232_626_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -128,20 +130,20 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: DdcPayouts AuthorisedCaller (r:0 w:1) fn set_authorised_caller() -> Weight { - Weight::from_ref_time(11_000_000_u64) + Weight::from_ref_time(90_258_000_u64) .saturating_add(RocksDbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_billing_report() -> Weight { - Weight::from_ref_time(19_000_000_u64) + Weight::from_ref_time(214_646_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_charging_customers() -> Weight { - Weight::from_ref_time(19_000_000_u64) + Weight::from_ref_time(228_676_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -153,9 +155,9 @@ impl WeightInfo for () { // Storage: DdcPayouts DebtorCustomers (r:1 w:1) /// The range of component `b` is `[1, 1000]`. fn send_charging_customers_batch(b: u32, ) -> Weight { - Weight::from_ref_time(12_333_820_u64) - // Standard Error: 298_759 - .saturating_add(Weight::from_ref_time(24_367_120_u64).saturating_mul(b as u64)) + Weight::from_ref_time(891_324_000_u64) + // Standard Error: 3_864_375 + .saturating_add(Weight::from_ref_time(558_679_506_u64).saturating_mul(b as u64)) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(b as u64))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -166,17 +168,19 @@ impl WeightInfo for () { // Storage: DdcClusters ClustersGovParams (r:1 w:0) // Storage: System Account (r:3 w:3) // Storage: DdcClusters Clusters (r:1 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:2 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) fn end_charging_customers() -> Weight { - Weight::from_ref_time(89_000_000_u64) - .saturating_add(RocksDbWeight::get().reads(10_u64)) + Weight::from_ref_time(1_691_550_000_u64) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn begin_rewarding_providers() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(234_686_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -185,25 +189,25 @@ impl WeightInfo for () { // Storage: System Account (r:2 w:2) /// The range of component `b` is `[1, 1000]`. fn send_rewarding_providers_batch(b: u32, ) -> Weight { - Weight::from_ref_time(32_000_000_u64) - // Standard Error: 5_087 - .saturating_add(Weight::from_ref_time(14_402_776_u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + Weight::from_ref_time(565_710_000_u64) + // Standard Error: 854_032 + .saturating_add(Weight::from_ref_time(408_429_599_u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(b as u64))) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn end_rewarding_providers() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(274_535_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } // Storage: DdcPayouts AuthorisedCaller (r:1 w:0) // Storage: DdcPayouts ActiveBillingReports (r:1 w:1) fn end_billing_report() -> Weight { - Weight::from_ref_time(18_000_000_u64) + Weight::from_ref_time(232_626_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/pallets/ddc-staking/Cargo.toml b/pallets/ddc-staking/Cargo.toml index 9dcad54c5..27608aa03 100644 --- a/pallets/ddc-staking/Cargo.toml +++ b/pallets/ddc-staking/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -ddc-primitives = { version = "0.1.0", default-features = false, path = "../../primitives" } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../../primitives" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31", optional = true } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/pallets/ddc-staking/src/mock.rs b/pallets/ddc-staking/src/mock.rs index 7ff3fbd1e..9017e9ef5 100644 --- a/pallets/ddc-staking/src/mock.rs +++ b/pallets/ddc-staking/src/mock.rs @@ -26,7 +26,7 @@ use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - Perbill, + Perquintill, }; use sp_std::collections::btree_map::BTreeMap; @@ -179,9 +179,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-staking/src/testing_utils.rs b/pallets/ddc-staking/src/testing_utils.rs index 21b35ffe1..c106e0bce 100644 --- a/pallets/ddc-staking/src/testing_utils.rs +++ b/pallets/ddc-staking/src/testing_utils.rs @@ -7,7 +7,7 @@ use ddc_primitives::{ use frame_benchmarking::account; use frame_support::traits::Currency; use frame_system::RawOrigin; -use sp_runtime::{traits::StaticLookup, Perbill}; +use sp_runtime::{traits::StaticLookup, Perquintill}; use sp_std::prelude::*; use crate::{Pallet as DdcStaking, *}; @@ -113,9 +113,9 @@ pub fn create_stash_controller_node_with_balance( let cluster_id = ClusterId::from([1; 20]); let cluster_params = ClusterParams { node_provider_auth_contract: Some(stash.clone()) }; let cluster_gov_params: ClusterGovParams, T::BlockNumber> = ClusterGovParams { - treasury_share: Perbill::default(), - validators_share: Perbill::default(), - cluster_reserve_share: Perbill::default(), + treasury_share: Perquintill::default(), + validators_share: Perquintill::default(), + cluster_reserve_share: Perquintill::default(), storage_bond_size: 10u32.into(), storage_chill_delay: 50u32.into(), storage_unbonding_delay: 50u32.into(), diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index eb7345653..2f579998f 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "ddc-primitives" -version = "0.1.0" +version = "4.8.2" edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } serde = { version = "1.0.136", default-features = false, features = ["derive"], optional = true } - sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 164f0338b..06a5dcfde 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -5,7 +5,11 @@ use scale_info::{prelude::vec::Vec, 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 const MILLICENTS: u128 = 100_000; +pub const CENTS: u128 = 1_000 * MILLICENTS; // assume this is worth about a cent. +pub const DOLLARS: u128 = 100 * CENTS; pub type ClusterId = H160; pub type DdcEra = u32; pub type BucketId = u64; @@ -22,9 +26,9 @@ pub struct ClusterParams { #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Default)] #[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 storage_bond_size: Balance, pub storage_chill_delay: BlockNumber, pub storage_unbonding_delay: BlockNumber, @@ -44,12 +48,12 @@ 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, } -#[derive(Debug, PartialEq)] +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] pub struct ClusterBondingParams { pub storage_bond_size: u128, pub storage_chill_delay: BlockNumber, diff --git a/runtime/cere-dev/Cargo.toml b/runtime/cere-dev/Cargo.toml index 6e8abc597..138115725 100644 --- a/runtime/cere-dev/Cargo.toml +++ b/runtime/cere-dev/Cargo.toml @@ -93,7 +93,7 @@ pallet-vesting = { default-features = false, git = "https://github.com/paritytec # cere dependencies cere-dev-runtime-constants = { path = "./constants", default-features = false } cere-runtime-common = { path = "../common", default-features = false } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } pallet-ddc-clusters = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-clusters" } pallet-ddc-customers = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-customers" } pallet-ddc-nodes = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-nodes" } diff --git a/runtime/cere-dev/src/lib.rs b/runtime/cere-dev/src/lib.rs index 66389b9f4..73eecafbc 100644 --- a/runtime/cere-dev/src/lib.rs +++ b/runtime/cere-dev/src/lib.rs @@ -81,8 +81,8 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, NumberFor, - OpaqueKeys, SaturatedConversion, StaticLookup, + self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, + Identity as IdentityConvert, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, @@ -1352,9 +1352,10 @@ impl pallet_ddc_payouts::Config for Runtime { type CustomerDepositor = DdcCustomers; type ClusterVisitor = DdcClusters; type TreasuryVisitor = TreasuryWrapper; - type ValidatorList = pallet_staking::UseValidatorsMap; + type NominatorsAndValidatorsList = pallet_staking::UseNominatorsAndValidatorsMap; type ClusterCreator = DdcClusters; type WeightInfo = pallet_ddc_payouts::weights::SubstrateWeight; + type VoteScoreToU64 = IdentityConvert; // used for UseNominatorsAndValidatorsMap } construct_runtime!( diff --git a/runtime/cere/Cargo.toml b/runtime/cere/Cargo.toml index f14f04142..e2fbb9b0f 100644 --- a/runtime/cere/Cargo.toml +++ b/runtime/cere/Cargo.toml @@ -93,7 +93,7 @@ pallet-vesting = { default-features = false, git = "https://github.com/paritytec # cere dependencies cere-runtime-common = { path = "../common", default-features = false } cere-runtime-constants = { path = "./constants", default-features = false } -ddc-traits = { version = "0.1.0", default-features = false, path = "../../traits" } +ddc-traits = { version = "4.8.2", default-features = false, path = "../../traits" } pallet-ddc-clusters = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-clusters" } pallet-ddc-customers = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-customers" } pallet-ddc-nodes = { version = "4.8.2", default-features = false, path = "../../pallets/ddc-nodes" } diff --git a/runtime/cere/src/lib.rs b/runtime/cere/src/lib.rs index 7d008b3c6..18ad72ca1 100644 --- a/runtime/cere/src/lib.rs +++ b/runtime/cere/src/lib.rs @@ -76,8 +76,8 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, NumberFor, - OpaqueKeys, SaturatedConversion, StaticLookup, + self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, + Identity as IdentityConvert, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, @@ -1337,9 +1337,10 @@ impl pallet_ddc_payouts::Config for Runtime { type CustomerDepositor = DdcCustomers; type ClusterVisitor = DdcClusters; type TreasuryVisitor = TreasuryWrapper; - type ValidatorList = pallet_staking::UseValidatorsMap; + type NominatorsAndValidatorsList = pallet_staking::UseNominatorsAndValidatorsMap; type ClusterCreator = DdcClusters; type WeightInfo = pallet_ddc_payouts::weights::SubstrateWeight; + type VoteScoreToU64 = IdentityConvert; // used for UseNominatorsAndValidatorsMap } impl pallet_ddc_staking::Config for Runtime { diff --git a/traits/Cargo.toml b/traits/Cargo.toml index e37e4d659..ffc5bdd7b 100644 --- a/traits/Cargo.toml +++ b/traits/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "ddc-traits" -version = "0.1.0" +version = "4.8.2" edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -ddc-primitives = { version = "0.1.0", default-features = false, path = "../primitives" } +ddc-primitives = { version = "4.8.2", default-features = false, path = "../primitives" } frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.31" } scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }