Skip to content

Commit

Permalink
Merge branch 'dev' into chore/redundant-versions
Browse files Browse the repository at this point in the history
  • Loading branch information
rakanalh authored Nov 20, 2023
2 parents fa2d45b + 08d4920 commit 29e0d81
Show file tree
Hide file tree
Showing 17 changed files with 1,178 additions and 223 deletions.
372 changes: 224 additions & 148 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ members = [
"pallets/ddc-customers",
"pallets/ddc-nodes",
"pallets/ddc-clusters",
"pallets/ddc-payouts",
"primitives",
]

Expand Down
15 changes: 14 additions & 1 deletion pallets/ddc-clusters/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
cluster::{Cluster, ClusterGovParams, ClusterParams},
node_provider_auth::{NodeProviderAuthContract, NodeProviderAuthContractError},
};
use ddc_primitives::{ClusterId, NodePubKey, NodeType};
use ddc_primitives::{ClusterId, ClusterPricingParams, NodePubKey, NodeType};
use ddc_traits::{
cluster::{ClusterVisitor, ClusterVisitorError},
staking::{StakingVisitor, StakingVisitorError},
Expand Down Expand Up @@ -271,6 +271,19 @@ pub mod pallet {
}
}

fn get_pricing_params(
cluster_id: &ClusterId,
) -> Result<ClusterPricingParams, ClusterVisitorError> {
let cluster_gov_params = ClustersGovParams::<T>::try_get(cluster_id)
.map_err(|_| ClusterVisitorError::ClusterGovParamsNotSet)?;
Ok(ClusterPricingParams {
unit_per_mb_stored: cluster_gov_params.unit_per_mb_stored,
unit_per_mb_streamed: cluster_gov_params.unit_per_mb_streamed,
unit_per_put_request: cluster_gov_params.unit_per_put_request,
unit_per_get_request: cluster_gov_params.unit_per_get_request,
})
}

fn get_chill_delay(
cluster_id: &ClusterId,
node_type: NodeType,
Expand Down
149 changes: 92 additions & 57 deletions pallets/ddc-customers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ mod tests;
use codec::{Decode, Encode, HasCompact};

use ddc_primitives::{BucketId, ClusterId};
use ddc_traits::cluster::ClusterVisitor;
use ddc_traits::{cluster::ClusterVisitor, customer::CustomerCharger};
use frame_support::{
parameter_types,
traits::{Currency, DefensiveSaturating, ExistenceRequirement},
BoundedVec, PalletId,
};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{AccountIdConversion, AtLeast32BitUnsigned, Saturating, Zero},
traits::{AccountIdConversion, AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Saturating, Zero},
RuntimeDebug, SaturatedConversion,
};
use sp_std::prelude::*;
Expand Down Expand Up @@ -117,28 +117,36 @@ impl<
/// Charge funds that were scheduled for unlocking.
///
/// Returns the updated ledger, and the amount actually charged.
fn charge_unlocking(mut self, value: Balance) -> (Self, Balance) {
fn charge_unlocking(mut self, value: Balance) -> Result<(Self, Balance), Error<T>> {
let mut unlocking_balance = Balance::zero();

while let Some(last) = self.unlocking.last_mut() {
if unlocking_balance + last.value <= value {
unlocking_balance += last.value;
self.active -= last.value;
let temp = unlocking_balance
.checked_add(&last.value)
.ok_or(Error::<T>::ArithmeticOverflow)?;
if temp <= value {
unlocking_balance = temp;
self.active =
self.active.checked_sub(&last.value).ok_or(Error::<T>::ArithmeticUnderflow)?;
self.unlocking.pop();
} else {
let diff = value - unlocking_balance;

unlocking_balance += diff;
self.active -= diff;
last.value -= diff;
let diff =
value.checked_sub(&unlocking_balance).ok_or(Error::<T>::ArithmeticUnderflow)?;

unlocking_balance =
unlocking_balance.checked_add(&diff).ok_or(Error::<T>::ArithmeticOverflow)?;
self.active =
self.active.checked_sub(&diff).ok_or(Error::<T>::ArithmeticUnderflow)?;
last.value =
last.value.checked_sub(&diff).ok_or(Error::<T>::ArithmeticUnderflow)?;
}

if unlocking_balance >= value {
break
}
}

(self, unlocking_balance)
Ok((self, unlocking_balance))
}
}

Expand Down Expand Up @@ -169,13 +177,18 @@ pub mod pallet {
/// Map from all (unlocked) "owner" accounts to the info regarding the staking.
#[pallet::storage]
#[pallet::getter(fn ledger)]
pub type Ledger<T: Config> =
StorageMap<_, Identity, T::AccountId, AccountsLedger<T::AccountId, BalanceOf<T>, T>>;
pub type Ledger<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId,
AccountsLedger<T::AccountId, BalanceOf<T>, T>,
>;

#[pallet::type_value]
pub fn DefaultBucketCount<T: Config>() -> BucketId {
0
}

#[pallet::storage]
#[pallet::getter(fn buckets_count)]
pub type BucketsCount<T: Config> =
Expand All @@ -196,12 +209,12 @@ pub mod pallet {
/// it will not be emitted for staking rewards when they are added to stake.
Deposited(T::AccountId, BalanceOf<T>),
/// An account has initiated unlock for amount. \[owner, amount\]
InitiatDepositUnlock(T::AccountId, BalanceOf<T>),
InitialDepositUnlock(T::AccountId, BalanceOf<T>),
/// An account has called `withdraw_unlocked_deposit` and removed unlocking chunks worth
/// `Balance` from the unlocking queue. \[owner, amount\]
Withdrawn(T::AccountId, BalanceOf<T>),
/// Total amount charged from all accounts to pay CDN nodes
Charged(BalanceOf<T>),
/// The account has been charged for the usage
Charged(T::AccountId, BalanceOf<T>),
/// Bucket with specific id created
BucketCreated(BucketId),
}
Expand All @@ -226,6 +239,12 @@ pub mod pallet {
BucketDoesNotExist,
/// DDC Cluster with provided id doesn't exist
ClusterDoesNotExist,
// unauthorised operation
Unauthorised,
// Arithmetic overflow
ArithmeticOverflow,
// Arithmetic underflow
ArithmeticUnderflow,
}

#[pallet::genesis_config]
Expand Down Expand Up @@ -257,7 +276,8 @@ pub mod pallet {
#[pallet::weight(10_000)]
pub fn create_bucket(origin: OriginFor<T>, cluster_id: ClusterId) -> DispatchResult {
let bucket_owner = ensure_signed(origin)?;
let cur_bucket_id = Self::buckets_count() + 1;
let cur_bucket_id =
Self::buckets_count().checked_add(1).ok_or(Error::<T>::ArithmeticOverflow)?;

<T as pallet::Config>::ClusterVisitor::ensure_cluster(&cluster_id)
.map_err(|_| Error::<T>::ClusterDoesNotExist)?;
Expand Down Expand Up @@ -328,8 +348,11 @@ pub mod pallet {

let owner_balance = <T as pallet::Config>::Currency::free_balance(&owner);
let extra = owner_balance.min(max_additional);
ledger.total += extra;
ledger.active += extra;
ledger.total =
ledger.total.checked_add(&extra).ok_or(Error::<T>::ArithmeticOverflow)?;
ledger.active =
ledger.active.checked_add(&extra).ok_or(Error::<T>::ArithmeticOverflow)?;

// Last check: the new active amount of ledger must be more than ED.
ensure!(
ledger.active >= <T as pallet::Config>::Currency::minimum_balance(),
Expand All @@ -356,7 +379,7 @@ pub mod pallet {
/// can co-exists at the same time. In that case, [`Call::withdraw_unlocked_deposit`] need
/// to be called first to remove some of the chunks (if possible).
///
/// Emits `InitiatDepositUnlock`.
/// Emits `InitialDepositUnlock`.
///
/// See also [`Call::withdraw_unlocked_deposit`].
#[pallet::weight(10_000)]
Expand All @@ -374,18 +397,20 @@ pub mod pallet {
let mut value = value.min(ledger.active);

if !value.is_zero() {
ledger.active -= value;
ledger.active =
ledger.active.checked_sub(&value).ok_or(Error::<T>::ArithmeticUnderflow)?;

// Avoid there being a dust balance left in the accounts system.
if ledger.active < <T as pallet::Config>::Currency::minimum_balance() {
value += ledger.active;
value =
value.checked_add(&ledger.active).ok_or(Error::<T>::ArithmeticOverflow)?;
ledger.active = Zero::zero();
}

let current_block = <frame_system::Pallet<T>>::block_number();
// Note: locking for extra block to allow for accounting
// block + configurable value - shouldn't overflow
let block = current_block + <T as pallet::Config>::UnlockingDelay::get();
log::debug!("Block for the unlock: {:?}", block);

if let Some(chunk) =
ledger.unlocking.last_mut().filter(|chunk| chunk.block == block)
Expand All @@ -403,7 +428,7 @@ pub mod pallet {

Self::update_ledger(&owner, &ledger);

Self::deposit_event(Event::<T>::InitiatDepositUnlock(ledger.owner, value));
Self::deposit_event(Event::<T>::InitialDepositUnlock(ledger.owner, value));
}
Ok(())
}
Expand Down Expand Up @@ -449,7 +474,8 @@ pub mod pallet {
if ledger.total < old_total {
log::debug!("Preparing for transfer");
// Already checked that this won't overflow by entry condition.
let value = old_total - ledger.total;
let value =
old_total.checked_sub(&ledger.total).ok_or(Error::<T>::ArithmeticUnderflow)?;

let account_id = Self::account_id();

Expand Down Expand Up @@ -511,40 +537,49 @@ pub mod pallet {

Ok(())
}
}

// Charge payments from content owners
pub fn charge_content_owners(
paying_accounts: Vec<BucketsDetails<BalanceOf<T>>>,
pricing: u128,
impl<T: Config> CustomerCharger<T> for Pallet<T> {
fn charge_content_owner(
content_owner: T::AccountId,
billing_vault: T::AccountId,
amount: u128,
) -> DispatchResult {
let mut total_charged = BalanceOf::<T>::zero();

for bucket_details in paying_accounts.iter() {
let bucket: Bucket<T::AccountId> = Self::buckets(bucket_details.bucket_id)
.ok_or(Error::<T>::BucketDoesNotExist)?;
let content_owner = bucket.owner_id;
let amount = bucket_details.amount * pricing.saturated_into::<BalanceOf<T>>();

let mut ledger = Self::ledger(&content_owner).ok_or(Error::<T>::NotOwner)?;
if ledger.active >= amount {
ledger.total -= amount;
ledger.active -= amount;
total_charged += amount;
Self::update_ledger(&content_owner, &ledger);
} else {
let diff = amount - ledger.active;
total_charged += ledger.active;
ledger.total -= ledger.active;
ledger.active = BalanceOf::<T>::zero();
let (ledger, charged) = ledger.charge_unlocking(diff);
Self::update_ledger(&content_owner, &ledger);
total_charged += charged;
}
}
log::debug!("Total charged: {:?}", &total_charged);
let mut ledger = Self::ledger(&content_owner).ok_or(Error::<T>::NotOwner)?;
let mut amount_to_deduct = amount.saturated_into::<BalanceOf<T>>();

ensure!(ledger.total >= ledger.active, Error::<T>::ArithmeticUnderflow);
if ledger.active >= amount_to_deduct {
ledger.active = ledger
.active
.checked_sub(&amount_to_deduct)
.ok_or(Error::<T>::ArithmeticUnderflow)?;
ledger.total = ledger
.total
.checked_sub(&amount_to_deduct)
.ok_or(Error::<T>::ArithmeticUnderflow)?;
Self::update_ledger(&content_owner, &ledger);
} else {
let diff = amount_to_deduct
.checked_sub(&ledger.active)
.ok_or(Error::<T>::ArithmeticUnderflow)?;
ledger.total = ledger
.total
.checked_sub(&ledger.active)
.ok_or(Error::<T>::ArithmeticUnderflow)?;
amount_to_deduct = ledger.active;
ledger.active = BalanceOf::<T>::zero();
let (ledger, _charged) = ledger.charge_unlocking(diff)?;
Self::update_ledger(&content_owner, &ledger);
};

Self::deposit_event(Event::<T>::Charged(total_charged));
log::debug!("Deposit event executed");
<T as pallet::Config>::Currency::transfer(
&Self::account_id(),
&billing_vault,
amount_to_deduct,
ExistenceRequirement::KeepAlive,
)?;
Self::deposit_event(Event::<T>::Charged(content_owner, amount_to_deduct));

Ok(())
}
Expand Down
13 changes: 12 additions & 1 deletion pallets/ddc-customers/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Test utilities
use crate::{self as pallet_ddc_customers, *};
use ddc_primitives::{NodePubKey, NodeType};
use ddc_primitives::{ClusterPricingParams, NodePubKey, NodeType};
use ddc_traits::cluster::{ClusterVisitor, ClusterVisitorError};

use frame_support::{
Expand Down Expand Up @@ -128,6 +128,17 @@ impl<T: Config> ClusterVisitor<T> for TestClusterVisitor {
) -> Result<T::BlockNumber, ClusterVisitorError> {
Ok(T::BlockNumber::from(10u32))
}

fn get_pricing_params(
_cluster_id: &ClusterId,
) -> Result<ClusterPricingParams, ClusterVisitorError> {
Ok(ClusterPricingParams {
unit_per_mb_stored: 1,
unit_per_mb_streamed: 2,
unit_per_put_request: 3,
unit_per_get_request: 4,
})
}
}

pub struct ExtBuilder;
Expand Down
42 changes: 42 additions & 0 deletions pallets/ddc-payouts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "pallet-ddc-payouts"
version = "4.8.1"
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" }
frame-benchmarking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30", optional = true }
frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
log = { version = "0.4.17", default-features = false }
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30", default-features = false }
sp-io = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
sp-runtime = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
sp-staking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
sp-std = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }

[dev-dependencies]
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
sp-tracing = { version = "5.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }
substrate-test-utils = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30" }

[features]
default = ["std"]
std = [
"codec/std",
"ddc-primitives/std",
"frame-support/std",
"frame-system/std",
"frame-benchmarking/std",
"scale-info/std",
"sp-io/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
"sp-core/std",
]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
Loading

0 comments on commit 29e0d81

Please sign in to comment.