Skip to content

Commit

Permalink
Merge pull request #103 from Cerebellum-Network/feat/ddc-core-entites…
Browse files Browse the repository at this point in the history
…-pallets

Base abstractions for DDC Clusters and DDC Nodes entities
  • Loading branch information
yahortsaryk authored Oct 17, 2023
2 parents cd7077b + 064bfba commit 69a2e2a
Show file tree
Hide file tree
Showing 12 changed files with 975 additions and 0 deletions.
41 changes: 41 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ members = [
"pallets/ddc-metrics-offchain-worker",
"pallets/ddc-validator",
"pallets/ddc-accounts",
"pallets/ddc-nodes",
"pallets/ddc-clusters",
]

[profile.release]
Expand Down
38 changes: 38 additions & 0 deletions pallets/ddc-clusters/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "pallet-ddc-clusters"
version = "4.8.1"
edition = "2021"

[dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] }
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-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" }
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30", default-features = false }
pallet-ddc-nodes = { version = "4.7.0", default-features = false, path = "../ddc-nodes" }

[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",
"frame-support/std",
"frame-system/std",
"frame-benchmarking/std",
"scale-info/std",
"sp-io/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
79 changes: 79 additions & 0 deletions pallets/ddc-clusters/src/cluster.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use crate::pallet::Error;
use codec::{Decode, Encode};
use frame_support::{pallet_prelude::*, parameter_types, BoundedVec};
use scale_info::TypeInfo;
use sp_core::hash::H160;
use sp_std::vec::Vec;

pub type ClusterId = H160;
parameter_types! {
pub MaxClusterParamsLen: u16 = 2048;
}

#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)]
pub struct Cluster<AccountId> {
pub cluster_id: ClusterId,
pub manager_id: AccountId,
pub props: ClusterProps<AccountId>,
}

#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)]
pub struct ClusterProps<AccountId> {
// this is a temporal way of storing cluster parameters as a stringified json,
// should be replaced with specific properties for cluster
pub params: BoundedVec<u8, MaxClusterParamsLen>,
pub node_provider_auth_contract: AccountId,
}

// ClusterParams includes Governance non-sensetive parameters only
#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)]
pub struct ClusterParams<AccountId> {
pub params: Vec<u8>,
pub node_provider_auth_contract: AccountId,
}

impl<AccountId> Cluster<AccountId> {
pub fn new(
cluster_id: ClusterId,
manager_id: AccountId,
cluster_params: ClusterParams<AccountId>,
) -> Result<Cluster<AccountId>, ClusterError> {
Ok(Cluster {
cluster_id,
manager_id,
props: ClusterProps {
params: match cluster_params.params.try_into() {
Ok(vec) => vec,
Err(_) => return Err(ClusterError::ClusterParamsExceedsLimit),
},
node_provider_auth_contract: cluster_params.node_provider_auth_contract,
},
})
}

pub fn set_params(
&mut self,
cluster_params: ClusterParams<AccountId>,
) -> Result<(), ClusterError> {
self.props = ClusterProps {
params: match cluster_params.params.try_into() {
Ok(vec) => vec,
Err(_) => return Err(ClusterError::ClusterParamsExceedsLimit),
},
node_provider_auth_contract: cluster_params.node_provider_auth_contract,
};
Ok(())
}
}

pub enum ClusterError {
ClusterParamsExceedsLimit,
}

impl<T> From<ClusterError> for Error<T> {
fn from(error: ClusterError) -> Self {
match error {
ClusterError::ClusterParamsExceedsLimit => Error::<T>::ClusterParamsExceedsLimit,
}
}
}
162 changes: 162 additions & 0 deletions pallets/ddc-clusters/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
//! # DDC Nodes Pallet
//!
//! The DDC Clusters pallet is used to manage DDC Clusters
//!
//! - [`Config`]
//! - [`Call`]
//! - [`Pallet`]
//!
//! ## GenesisConfig
//!
//! The DDC Clusters pallet depends on the [`GenesisConfig`]. The
//! `GenesisConfig` is optional and allow to set some initial nodes in DDC.

#![cfg_attr(not(feature = "std"), no_std)]
#![recursion_limit = "256"]

use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
pub use pallet::*;
use pallet_ddc_nodes::{NodePubKey, NodeRepository, NodeTrait};
mod cluster;

pub use crate::cluster::{Cluster, ClusterError, ClusterId, ClusterParams};

#[frame_support::pallet]
pub mod pallet {
use super::*;

#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type NodeRepository: NodeRepository<Self>;
}

#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
ClusterCreated { cluster_id: ClusterId },
ClusterNodeAdded { cluster_id: ClusterId, node_pub_key: NodePubKey },
ClusterNodeRemoved { cluster_id: ClusterId, node_pub_key: NodePubKey },
ClusterParamsSet { cluster_id: ClusterId },
}

#[pallet::error]
pub enum Error<T> {
ClusterAlreadyExists,
ClusterDoesNotExist,
ClusterParamsExceedsLimit,
AttemptToAddNonExistentNode,
AttemptToRemoveNonExistentNode,
NodeIsAlreadyAssigned,
NodeIsNotAssigned,
OnlyClusterManager,
}

#[pallet::storage]
#[pallet::getter(fn clusters)]
pub type Clusters<T: Config> =
StorageMap<_, Blake2_128Concat, ClusterId, Cluster<T::AccountId>>;

#[pallet::storage]
#[pallet::getter(fn clusters_nodes)]
pub type ClustersNodes<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
ClusterId,
Blake2_128Concat,
NodePubKey,
bool,
ValueQuery,
>;

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(10_000)]
pub fn create_cluster(
origin: OriginFor<T>,
cluster_id: ClusterId,
cluster_params: ClusterParams<T::AccountId>,
) -> DispatchResult {
let caller_id = ensure_signed(origin)?;
let cluster = Cluster::new(cluster_id.clone(), caller_id, cluster_params)
.map_err(|e: ClusterError| Into::<Error<T>>::into(ClusterError::from(e)))?;
ensure!(!Clusters::<T>::contains_key(&cluster_id), Error::<T>::ClusterAlreadyExists);
Clusters::<T>::insert(cluster_id.clone(), cluster);
Self::deposit_event(Event::<T>::ClusterCreated { cluster_id });
Ok(())
}

#[pallet::weight(10_000)]
pub fn add_node(
origin: OriginFor<T>,
cluster_id: ClusterId,
node_pub_key: NodePubKey,
) -> DispatchResult {
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>::AttemptToAddNonExistentNode)?;
ensure!(node.get_cluster_id().is_none(), Error::<T>::NodeIsAlreadyAssigned);

// todo: check that node is authorized by the 'NodeProviderAuthSC' contract
// todo: check that node provider has a bond for this 'cluster_id' and 'node_pub_key'

node.set_cluster_id(Some(cluster_id.clone()));
T::NodeRepository::update(node).map_err(|_| Error::<T>::AttemptToAddNonExistentNode)?;
ClustersNodes::<T>::insert(cluster_id.clone(), node_pub_key.clone(), true);
Self::deposit_event(Event::<T>::ClusterNodeAdded { cluster_id, node_pub_key });

Ok(())
}

#[pallet::weight(10_000)]
pub fn remove_node(
origin: OriginFor<T>,
cluster_id: ClusterId,
node_pub_key: NodePubKey,
) -> DispatchResult {
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.clone(), node_pub_key.clone());
Self::deposit_event(Event::<T>::ClusterNodeRemoved { cluster_id, node_pub_key });

Ok(())
}

// Sets Governance non-sensetive parameters only
#[pallet::weight(10_000)]
pub fn set_cluster_params(
origin: OriginFor<T>,
cluster_id: ClusterId,
cluster_params: ClusterParams<T::AccountId>,
) -> DispatchResult {
let caller_id = ensure_signed(origin)?;
let mut cluster =
Clusters::<T>::try_get(&cluster_id).map_err(|_| Error::<T>::ClusterDoesNotExist)?;
ensure!(cluster.manager_id == caller_id, Error::<T>::OnlyClusterManager);
cluster
.set_params(cluster_params)
.map_err(|e: ClusterError| Into::<Error<T>>::into(ClusterError::from(e)))?;
Clusters::<T>::insert(cluster_id.clone(), cluster);
Self::deposit_event(Event::<T>::ClusterParamsSet { cluster_id });

Ok(())
}
}
}
37 changes: 37 additions & 0 deletions pallets/ddc-nodes/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "pallet-ddc-nodes"
version = "4.8.1"
edition = "2021"

[dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] }
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-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" }
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.30", default-features = false }

[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",
"frame-support/std",
"frame-system/std",
"frame-benchmarking/std",
"scale-info/std",
"sp-io/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
Loading

0 comments on commit 69a2e2a

Please sign in to comment.