Skip to content

Commit

Permalink
chore: PR #150 is backported
Browse files Browse the repository at this point in the history
  • Loading branch information
yahortsaryk committed Dec 8, 2023
1 parent a08e30d commit 955aa46
Show file tree
Hide file tree
Showing 17 changed files with 655 additions and 91 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

134 changes: 104 additions & 30 deletions pallets/ddc-clusters/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use crate::{
node_provider_auth::{NodeProviderAuthContract, NodeProviderAuthContractError},
};
use ddc_primitives::{
ClusterFeesParams, ClusterGovParams, ClusterId, ClusterParams, ClusterPricingParams,
NodePubKey, NodeType,
ClusterBondingParams, ClusterFeesParams, ClusterGovParams, ClusterId, ClusterParams,
ClusterPricingParams, NodePubKey, NodeType,
};
use ddc_traits::{
cluster::{ClusterCreator, ClusterVisitor, ClusterVisitorError},
Expand All @@ -52,6 +52,7 @@ pub type BalanceOf<T> =
#[frame_support::pallet]
pub mod pallet {
use super::*;
use ddc_traits::cluster::{ClusterManager, ClusterManagerError};
use pallet_contracts::chain_extension::UncheckedFrom;

#[pallet::pallet]
Expand Down Expand Up @@ -83,12 +84,12 @@ pub mod pallet {
ClusterDoesNotExist,
ClusterParamsExceedsLimit,
AttemptToAddNonExistentNode,
AttemptToAddAlreadyAssignedNode,
AttemptToRemoveNonExistentNode,
NodeIsAlreadyAssigned,
NodeIsNotAssigned,
AttemptToRemoveNotAssignedNode,
OnlyClusterManager,
NodeIsNotAuthorized,
NodeHasNoStake,
NodeHasNoActivatedStake,
NodeStakeIsInvalid,
/// Cluster candidate should not plan to chill.
NodeChillingIsProhibited,
Expand Down Expand Up @@ -150,28 +151,30 @@ pub mod pallet {
let caller_id = ensure_signed(origin)?;
let cluster =
Clusters::<T>::try_get(cluster_id).map_err(|_| Error::<T>::ClusterDoesNotExist)?;
ensure!(cluster.manager_id == caller_id, Error::<T>::OnlyClusterManager);

// Node with this node with this public key exists.
let mut node = T::NodeRepository::get(node_pub_key.clone())
.map_err(|_| Error::<T>::AttemptToAddNonExistentNode)?;
ensure!(node.get_cluster_id().is_none(), Error::<T>::NodeIsAlreadyAssigned);
ensure!(cluster.manager_id == caller_id, Error::<T>::OnlyClusterManager);

// Sufficient funds are locked at the DDC Staking module.
let has_stake = T::StakingVisitor::node_has_stake(&node_pub_key, &cluster_id)
.map_err(Into::<Error<T>>::into)?;
ensure!(has_stake, Error::<T>::NodeHasNoStake);
let has_activated_stake =
T::StakingVisitor::has_activated_stake(&node_pub_key, &cluster_id)
.map_err(Into::<Error<T>>::into)?;
ensure!(has_activated_stake, Error::<T>::NodeHasNoActivatedStake);

// Candidate is not planning to pause operations any time soon.
let is_chilling = T::StakingVisitor::node_is_chilling(&node_pub_key)
let has_chilling_attempt = T::StakingVisitor::has_chilling_attempt(&node_pub_key)
.map_err(Into::<Error<T>>::into)?;
ensure!(!is_chilling, Error::<T>::NodeChillingIsProhibited);
ensure!(!has_chilling_attempt, Error::<T>::NodeChillingIsProhibited);

// Cluster extension smart contract allows joining.
let auth_contract = NodeProviderAuthContract::<T>::new(
cluster.props.node_provider_auth_contract,
caller_id,
);

// Node with this node with this public key exists.
let node = T::NodeRepository::get(node_pub_key.clone())
.map_err(|_| Error::<T>::AttemptToAddNonExistentNode)?;

let is_authorized = auth_contract
.is_authorized(
node.get_provider_id().to_owned(),
Expand All @@ -182,9 +185,8 @@ pub mod pallet {
ensure!(is_authorized, Error::<T>::NodeIsNotAuthorized);

// Add node to the cluster.
node.set_cluster_id(Some(cluster_id));
T::NodeRepository::update(node).map_err(|_| Error::<T>::AttemptToAddNonExistentNode)?;
ClustersNodes::<T>::insert(cluster_id, node_pub_key.clone(), true);
<Self as ClusterManager<T>>::add_node(&cluster_id, &node_pub_key)
.map_err(Into::<Error<T>>::into)?;
Self::deposit_event(Event::<T>::ClusterNodeAdded { cluster_id, node_pub_key });

Ok(())
Expand All @@ -199,14 +201,12 @@ pub mod pallet {
let caller_id = ensure_signed(origin)?;
let cluster =
Clusters::<T>::try_get(cluster_id).map_err(|_| Error::<T>::ClusterDoesNotExist)?;

ensure!(cluster.manager_id == caller_id, Error::<T>::OnlyClusterManager);
let mut node = T::NodeRepository::get(node_pub_key.clone())
.map_err(|_| Error::<T>::AttemptToRemoveNonExistentNode)?;
ensure!(node.get_cluster_id() == &Some(cluster_id), Error::<T>::NodeIsNotAssigned);
node.set_cluster_id(None);
T::NodeRepository::update(node)
.map_err(|_| Error::<T>::AttemptToRemoveNonExistentNode)?;
ClustersNodes::<T>::remove(cluster_id, node_pub_key.clone());

// Remove node from the cluster.
<Self as ClusterManager<T>>::remove_node(&cluster_id, &node_pub_key)
.map_err(Into::<Error<T>>::into)?;
Self::deposit_event(Event::<T>::ClusterNodeRemoved { cluster_id, node_pub_key });

Ok(())
Expand Down Expand Up @@ -269,10 +269,6 @@ pub mod pallet {
}

impl<T: Config> ClusterVisitor<T> for Pallet<T> {
fn cluster_has_node(cluster_id: &ClusterId, node_pub_key: &NodePubKey) -> bool {
ClustersNodes::<T>::get(cluster_id, node_pub_key).is_some()
}

fn ensure_cluster(cluster_id: &ClusterId) -> Result<(), ClusterVisitorError> {
Clusters::<T>::get(cluster_id)
.map(|_| ())
Expand Down Expand Up @@ -349,6 +345,69 @@ pub mod pallet {
NodeType::CDN => Ok(cluster_gov_params.cdn_unbonding_delay),
}
}

fn get_bonding_params(
cluster_id: &ClusterId,
) -> Result<ClusterBondingParams<T::BlockNumber>, ClusterVisitorError> {
let cluster_gov_params = ClustersGovParams::<T>::try_get(cluster_id)
.map_err(|_| ClusterVisitorError::ClusterGovParamsNotSet)?;
Ok(ClusterBondingParams {
cdn_bond_size: cluster_gov_params.cdn_bond_size.saturated_into::<u128>(),
cdn_chill_delay: cluster_gov_params.cdn_chill_delay,
cdn_unbonding_delay: cluster_gov_params.cdn_unbonding_delay,
storage_bond_size: cluster_gov_params.storage_bond_size.saturated_into::<u128>(),
storage_chill_delay: cluster_gov_params.storage_chill_delay,
storage_unbonding_delay: cluster_gov_params.storage_unbonding_delay,
})
}
}

impl<T: Config> ClusterManager<T> for Pallet<T> {
fn contains_node(cluster_id: &ClusterId, node_pub_key: &NodePubKey) -> bool {
ClustersNodes::<T>::get(cluster_id, node_pub_key).is_some()
}

fn add_node(
cluster_id: &ClusterId,
node_pub_key: &NodePubKey,
) -> Result<(), ClusterManagerError> {
let mut node = T::NodeRepository::get(node_pub_key.clone())
.map_err(|_| ClusterManagerError::AttemptToAddNonExistentNode)?;

ensure!(
node.get_cluster_id().is_none(),
ClusterManagerError::AttemptToAddAlreadyAssignedNode
);

node.set_cluster_id(Some(*cluster_id));
T::NodeRepository::update(node)
.map_err(|_| ClusterManagerError::AttemptToAddNonExistentNode)?;

ClustersNodes::<T>::insert(cluster_id, node_pub_key.clone(), true);

Ok(())
}

fn remove_node(
cluster_id: &ClusterId,
node_pub_key: &NodePubKey,
) -> Result<(), ClusterManagerError> {
let mut node = T::NodeRepository::get(node_pub_key.clone())
.map_err(|_| ClusterManagerError::AttemptToRemoveNonExistentNode)?;

ensure!(
node.get_cluster_id() == &Some(*cluster_id),
ClusterManagerError::AttemptToRemoveNotAssignedNode
);

node.set_cluster_id(None);
T::NodeRepository::update(node)
.map_err(|_| ClusterManagerError::AttemptToRemoveNonExistentNode)?;

ClustersNodes::<T>::remove(cluster_id, node_pub_key.clone());

Ok(())
}
}

impl<T: Config> ClusterCreator<T, BalanceOf<T>> for Pallet<T>
Expand All @@ -375,7 +434,7 @@ pub mod pallet {
impl<T> From<StakingVisitorError> for Error<T> {
fn from(error: StakingVisitorError) -> Self {
match error {
StakingVisitorError::NodeStakeDoesNotExist => Error::<T>::NodeHasNoStake,
StakingVisitorError::NodeStakeDoesNotExist => Error::<T>::NodeHasNoActivatedStake,
StakingVisitorError::NodeStakeIsInBadState => Error::<T>::NodeStakeIsInvalid,
}
}
Expand All @@ -389,4 +448,19 @@ pub mod pallet {
}
}
}

impl<T> From<ClusterManagerError> for Error<T> {
fn from(error: ClusterManagerError) -> Self {
match error {
ClusterManagerError::AttemptToRemoveNotAssignedNode =>
Error::<T>::AttemptToRemoveNotAssignedNode,
ClusterManagerError::AttemptToRemoveNonExistentNode =>
Error::<T>::AttemptToRemoveNonExistentNode,
ClusterManagerError::AttemptToAddNonExistentNode =>
Error::<T>::AttemptToAddNonExistentNode,
ClusterManagerError::AttemptToAddAlreadyAssignedNode =>
Error::<T>::AttemptToAddAlreadyAssignedNode,
}
}
}
}
8 changes: 6 additions & 2 deletions pallets/ddc-clusters/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ impl pallet_timestamp::Config for Test {

impl pallet_ddc_nodes::Config for Test {
type RuntimeEvent = RuntimeEvent;
type StakingVisitor = TestStakingVisitor;
}

impl crate::pallet::Config for Test {
Expand All @@ -194,13 +195,16 @@ pub(crate) type DdcStakingCall = crate::Call<Test>;
pub(crate) type TestRuntimeCall = <Test as frame_system::Config>::RuntimeCall;
pub struct TestStakingVisitor;
impl<T: Config> StakingVisitor<T> for TestStakingVisitor {
fn node_has_stake(
fn has_activated_stake(
_node_pub_key: &NodePubKey,
_cluster_id: &ClusterId,
) -> Result<bool, StakingVisitorError> {
Ok(true)
}
fn node_is_chilling(_node_pub_key: &NodePubKey) -> Result<bool, StakingVisitorError> {
fn has_stake(_node_pub_key: &NodePubKey) -> bool {
true
}
fn has_chilling_attempt(_node_pub_key: &NodePubKey) -> Result<bool, StakingVisitorError> {
Ok(false)
}
}
Expand Down
4 changes: 2 additions & 2 deletions pallets/ddc-clusters/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ fn add_and_delete_node_works() {
ClusterId::from([1; 20]),
NodePubKey::CDNPubKey(AccountId::from([4; 32])),
),
Error::<Test>::NodeIsAlreadyAssigned
Error::<Test>::AttemptToAddAlreadyAssignedNode
);

// Checking that event was emitted
Expand Down Expand Up @@ -218,7 +218,7 @@ fn add_and_delete_node_works() {
ClusterId::from([1; 20]),
NodePubKey::CDNPubKey(AccountId::from([4; 32])),
),
Error::<Test>::NodeIsNotAssigned
Error::<Test>::AttemptToRemoveNotAssignedNode
);

pub const CTOR_SELECTOR: [u8; 4] = hex!("9bae9d5e");
Expand Down
70 changes: 64 additions & 6 deletions pallets/ddc-customers/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
use crate::{self as pallet_ddc_customers, *};
use ddc_primitives::{
ClusterFeesParams, ClusterGovParams, ClusterId, ClusterParams, ClusterPricingParams,
NodePubKey, NodeType,
ClusterBondingParams, ClusterFeesParams, ClusterGovParams, ClusterId, ClusterParams,
ClusterPricingParams, NodePubKey, NodeType,
};
use ddc_traits::cluster::{ClusterCreator, ClusterVisitor, ClusterVisitorError};
use ddc_traits::cluster::{
ClusterCreator, ClusterManager, ClusterManagerError, ClusterVisitor, ClusterVisitorError,
};

use frame_support::{
construct_runtime, parameter_types,
traits::{ConstU32, ConstU64, Everything},
Expand Down Expand Up @@ -109,9 +112,6 @@ impl crate::pallet::Config for Test {

pub struct TestClusterVisitor;
impl<T: Config> ClusterVisitor<T> for TestClusterVisitor {
fn cluster_has_node(_cluster_id: &ClusterId, _node_pub_key: &NodePubKey) -> bool {
true
}
fn ensure_cluster(_cluster_id: &ClusterId) -> Result<(), ClusterVisitorError> {
Ok(())
}
Expand Down Expand Up @@ -158,6 +158,64 @@ impl<T: Config> ClusterVisitor<T> for TestClusterVisitor {
) -> Result<T::AccountId, ClusterVisitorError> {
Err(ClusterVisitorError::ClusterDoesNotExist)
}

fn get_bonding_params(
cluster_id: &ClusterId,
) -> Result<ClusterBondingParams<T::BlockNumber>, ClusterVisitorError> {
Ok(ClusterBondingParams {
cdn_bond_size: <TestClusterVisitor as ClusterVisitor<T>>::get_bond_size(
cluster_id,
NodeType::CDN,
)
.unwrap_or_default(),
cdn_chill_delay: <TestClusterVisitor as ClusterVisitor<T>>::get_chill_delay(
cluster_id,
NodeType::CDN,
)
.unwrap_or_default(),
cdn_unbonding_delay: <TestClusterVisitor as ClusterVisitor<T>>::get_unbonding_delay(
cluster_id,
NodeType::CDN,
)
.unwrap_or_default(),
storage_bond_size: <TestClusterVisitor as ClusterVisitor<T>>::get_bond_size(
cluster_id,
NodeType::Storage,
)
.unwrap_or_default(),
storage_chill_delay: <TestClusterVisitor as ClusterVisitor<T>>::get_chill_delay(
cluster_id,
NodeType::Storage,
)
.unwrap_or_default(),
storage_unbonding_delay:
<TestClusterVisitor as ClusterVisitor<T>>::get_unbonding_delay(
cluster_id,
NodeType::Storage,
)
.unwrap_or_default(),
})
}
}

pub struct TestClusterManager;
impl<T: Config> ClusterManager<T> for TestClusterManager {
fn contains_node(_cluster_id: &ClusterId, _node_pub_key: &NodePubKey) -> bool {
true
}
fn add_node(
_cluster_id: &ClusterId,
_node_pub_key: &NodePubKey,
) -> Result<(), ClusterManagerError> {
Ok(())
}

fn remove_node(
_cluster_id: &ClusterId,
_node_pub_key: &NodePubKey,
) -> Result<(), ClusterManagerError> {
Ok(())
}
}

pub struct TestClusterCreator;
Expand Down
Loading

0 comments on commit 955aa46

Please sign in to comment.