Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ extern crate parity_codec_derive;

pub mod governance;
use governance::{election, council, proposals};
pub mod storage;
use storage::{data_object_type_registry};
mod memo;
mod traits;
mod membership;
use membership::members;
mod traits;
mod migration;

use rstd::prelude::*;
Expand Down Expand Up @@ -230,6 +232,11 @@ impl memo::Trait for Runtime {
type Event = Event;
}

impl storage::data_object_type_registry::Trait for Runtime {
type Event = Event;
type DataObjectTypeID = u64;
}

impl members::Trait for Runtime {
type Event = Event;
type MemberId = u64;
Expand Down Expand Up @@ -263,6 +270,7 @@ construct_runtime!(
Memo: memo::{Module, Call, Storage, Event<T>},
Members: members::{Module, Call, Storage, Event<T>, Config<T>},
Migration: migration::{Module, Call, Storage, Event<T>},
DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
}
);

Expand Down
154 changes: 154 additions & 0 deletions src/storage/data_object_type_registry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#![cfg_attr(not(feature = "std"), no_std)]

use rstd::prelude::*;
use parity_codec::Codec;
use parity_codec_derive::{Encode, Decode};
use srml_support::{StorageMap, StorageValue, decl_module, decl_storage, decl_event, ensure, Parameter};
use runtime_primitives::traits::{SimpleArithmetic, As, Member, MaybeSerializeDebug, MaybeDebug};
use system::{self, ensure_root};
use crate::traits;

pub trait Trait: system::Trait + MaybeDebug
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Rust there is a convention to put opening { on the same line with a preceding code:

Suggested change
pub trait Trait: system::Trait + MaybeDebug
pub trait Trait: system::Trait + MaybeDebug {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with changing that, but you're likely going to see this a lot from me :)

{
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;

type DataObjectTypeID: Parameter + Member + SimpleArithmetic + Codec + Default + Copy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By following Substrate and our naming convention for IDs, it should be: ID -> Id

Suggested change
type DataObjectTypeID: Parameter + Member + SimpleArithmetic + Codec + Default + Copy
type DataObjectTypeId: Parameter + Member + SimpleArithmetic + Codec + Default + Copy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a naming convention that I've seen a lot in Java, and it's pretty stupid. ID is not a word, it's an abbreviation, so CamelCasing it makes no sense at all. Still, I will change it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a quote from ID article on Wiki:

ID, Id, id or I.D. may refer to:

  • Identity document, any document used to verify a person's identity
  • Identifier, a symbol which uniquely identifies an object or record

I believe that in our cases (AccounId, MemberId, ProposalId) an Id stands for Identifier (i.e. id_entifier. ID could be considered as an abbreviation only in case if we reffer to I_dentity D_ocument – that is not our case at all.

+ As<usize> + As<u64> + MaybeSerializeDebug + PartialEq;
}


static MSG_REQUIRE_NEW_DO_TYPE: &str = "New Data Object Type required; the provided one seems to be in use already!";
static MSG_DO_TYPE_NOT_FOUND: &str = "Data Object Type with the given ID not found!";
static MSG_REQUIRE_DO_TYPE_ID: &str = "Can only update Data Object Types that are already registered (with an ID)!";

const DEFAULT_FIRST_DATA_OBJECT_TYPE_ID: u64 = 1;

#[derive(Clone, Encode, Decode, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct DataObjectType<T: Trait>
{
// If the OT is registered, an ID must exist, otherwise it's a new OT.
pub id: Option<T::DataObjectTypeID>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest changing id type to just T::DataObjectTypeId and creating an additional struct just for updates:

pub struct DataObjectTypeUpdate<T: Trait> {
  description: Option<Vec<u8>>,
  active: Option<bool>,
}

And in update_* function, update only those fields of stored value that are Some in DataObjectTypeUpdate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, why? I suppose it may keep transaction sizes down. I suppose that could be worth it, but is that the rationale?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tx size is certainly a benefit, but I think the rationale behind alex's suggestion is so that you wouldn't have to change the function signature in the future if you introduce new fields to theDataObjectType type. (I don't want to put words in his mouth but that is how I understood it when he recommended the same for the members module update_profile() method)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually didn't look at the function signature (i assumed there was one parameter per field).. so my point doesn't actually make sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because object's id is used quite often (at least on UI: list stored objects, view details of stored objects, etc.) and having it as an Option will require additional check storedObj.id.isSome ? ...then : else... everywhere. Comparing to update – this operation is rate and exists only on Update Form.

pub description: Vec<u8>,
pub active: bool,

// TODO in future releases
// - maximum size
// - replication factor
// - storage tranches (empty is ok)
}

decl_storage! {
trait Store for Module<T: Trait> as DataObjectTypeRegistry
{
// Start at this value
pub FirstDataObjectTypeID get(first_data_object_type_id) config(first_data_object_type_id): T::DataObjectTypeID = T::DataObjectTypeID::sa(DEFAULT_FIRST_DATA_OBJECT_TYPE_ID);

// Increment
pub NextDataObjectTypeID get(next_data_object_type_id) build(|config: &GenesisConfig<T>| config.first_data_object_type_id): T::DataObjectTypeID = T::DataObjectTypeID::sa(DEFAULT_FIRST_DATA_OBJECT_TYPE_ID);

// Mapping of Data object types
pub DataObjectTypeMap get(data_object_type): map T::DataObjectTypeID => Option<DataObjectType<T>>;
}
}

decl_event! {
pub enum Event<T> where
<T as Trait>::DataObjectTypeID
{
DataObjectTypeAdded(DataObjectTypeID),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Registered instead of Added? Such as a function is register_data_object_type

Suggested change
DataObjectTypeAdded(DataObjectTypeID),
DataObjectTypeRegistered(DataObjectTypeID),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, will change.

DataObjectTypeUpdated(DataObjectTypeID),
}
}



impl<T: Trait> traits::IsActiveDataObjectType<T> for Module<T>
{
fn is_active_data_object_type(which: &T::DataObjectTypeID) -> bool
{
match Self::ensure_data_object_type(*which)
{
Ok(do_type) => do_type.active,
Err(_err) => false
}
}
}


decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin
{
fn deposit_event<T>() = default;

pub fn register_data_object_type(origin, data_object_type: DataObjectType<T>)
{
ensure_root(origin)?;
ensure!(data_object_type.id.is_none(), MSG_REQUIRE_NEW_DO_TYPE);

let new_do_type_id = Self::next_data_object_type_id();
let do_type: DataObjectType<T> = DataObjectType {
id: Some(new_do_type_id),
description: data_object_type.description.clone(),
active: data_object_type.active,
};

<DataObjectTypeMap<T>>::insert(new_do_type_id, do_type);
<NextDataObjectTypeID<T>>::mutate(|n| { *n += T::DataObjectTypeID::sa(1); });

Self::deposit_event(RawEvent::DataObjectTypeAdded(new_do_type_id));
}

pub fn update_data_object_type(origin, data_object_type: DataObjectType<T>)
{
ensure_root(origin)?;
ensure!(data_object_type.id.is_some(), MSG_REQUIRE_DO_TYPE_ID);

let id = data_object_type.id.unwrap();
let mut do_type = Self::ensure_data_object_type(id)?;

do_type.description = data_object_type.description.clone();
do_type.active = data_object_type.active;

<DataObjectTypeMap<T>>::insert(id, do_type);

Self::deposit_event(RawEvent::DataObjectTypeUpdated(id));
}

// Activate and deactivate functions as separate functions, because
// toggling DO types is likely a more common operation than updating
// other aspects.
pub fn activate_data_object_type(origin, id: T::DataObjectTypeID)
{
ensure_root(origin)?;
let mut do_type = Self::ensure_data_object_type(id)?;

do_type.active = true;

<DataObjectTypeMap<T>>::insert(id, do_type);

Self::deposit_event(RawEvent::DataObjectTypeUpdated(id));
}

pub fn deactivate_data_object_type(origin, id: T::DataObjectTypeID)
{
ensure_root(origin)?;
let mut do_type = Self::ensure_data_object_type(id)?;

do_type.active = false;

<DataObjectTypeMap<T>>::insert(id, do_type);

Self::deposit_event(RawEvent::DataObjectTypeUpdated(id));
}

}
}

impl <T: Trait> Module<T>
{
fn ensure_data_object_type(id: T::DataObjectTypeID) -> Result<DataObjectType<T>, &'static str>
{
return Self::data_object_type(&id).ok_or(MSG_DO_TYPE_NOT_FOUND);
}
}
89 changes: 89 additions & 0 deletions src/storage/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#![cfg(test)]

use rstd::prelude::*;
pub use super::{data_object_type_registry};
pub use system;

pub use primitives::{H256, Blake2Hasher};
pub use runtime_primitives::{
BuildStorage,
traits::{BlakeTwo256, OnFinalise, IdentityLookup},
testing::{Digest, DigestItem, Header, UintAuthorityId}
};

use srml_support::{impl_outer_origin, impl_outer_event};

impl_outer_origin! {
pub enum Origin for Test {}
}

impl_outer_event! {
pub enum MetaEvent for Test
{
data_object_type_registry<T>,
}
}

// For testing the module, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of modules we want to use.
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Test;
impl system::Trait for Test
{
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
type Event = MetaEvent;
type Log = DigestItem;
type Lookup = IdentityLookup<u64>;
}
impl data_object_type_registry::Trait for Test
{
type Event = MetaEvent;
type DataObjectTypeID = u64;
}

pub struct ExtBuilder
{
first_data_object_type_id: u64,
}

impl Default for ExtBuilder
{
fn default() -> Self
{
Self {
first_data_object_type_id: 1,
}
}
}

impl ExtBuilder
{
pub fn first_data_object_type_id(mut self, first_data_object_type_id: u64) -> Self
{
self.first_data_object_type_id = first_data_object_type_id;
self
}
pub fn build(self) -> runtime_io::TestExternalities<Blake2Hasher>
{
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap().0;

t.extend(data_object_type_registry::GenesisConfig::<Test>{
first_data_object_type_id: self.first_data_object_type_id,
}.build_storage().unwrap().0);

t.into()
}
}


pub type System = system::Module<Test>;
pub type TestDataObjectTypeRegistry = data_object_type_registry::Module<Test>;
pub type TestDataObjectType = data_object_type_registry::DataObjectType<Test>;
6 changes: 6 additions & 0 deletions src/storage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub mod data_object_type_registry;

mod mock;
mod tests;
Loading