Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pallet-sense #1

Merged
merged 7 commits into from
Feb 11, 2022
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
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Cargo
# will have compiled files and executables
**/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

.DS_Store
.idea

# Intentional not commiting this file to allow this repo to be added as a submodule
/Cargo.toml
47 changes: 47 additions & 0 deletions sense/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[package]
name = 'pallet-sense'
version = '0.1.0'
authors = ['2075']
edition = '2018'
license = 'GPL-3.0-or-later'
description = 'Pallet Sense aggregates datapoints to reflect user experience and behaviour'
repository = 'https://github.com/gamedaoco/gamedao-protocol'

[package.metadata.substrate]
categories = [
'zero',
'core'
]

[dependencies]
serde = { version = "1.0.124", optional = true }
codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false, optional = true }

[dev-dependencies]
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" }

[features]
default = ['std']
runtime-benchmarks = ['frame-benchmarking']
std = [
'codec/std',
'serde/std',
'scale-info/std',

'frame-support/std',
'frame-system/std',
'frame-benchmarking/std',

'sp-core/std',
'sp-std/std',
'sp-runtime/std',
]
try-runtime = ['frame-support/try-runtime']
26 changes: 26 additions & 0 deletions sense/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# zero sensenet

## Identity and Reputation

Every entity in ZERO METAVERSE needs to provide initial identity information to create an ecosystem wide decentralised identity (DID). This allows for platform operation in a legal manner, provides transparency and guarantees for the community.

The identity system is bound to ZERO as a network layer, which provides identity and payment flow for all participants.

Identity is cryptographically abstracted away to make it inefficient to reveal private data of a user without its consent.

In certain cases, users are required to reveal their identity to proceed in e.g. monetary transactions (KYC/AML) or audits when participating in certain protocol execution.

Identity comes with additional features for the ecosystems connected to ZERO, namely trust, reputation and experience metrics, which are powered by:

- Provision of social identifiers strengthening the Trust (T) level of an identity
- Continuous contribution of activity into their experience levels (XP)
- Social feedback of other ecosystem participants, contributing to the reputation (REP) of an identity

These all together, T, XP, REP and the opaque identity provide increased trust and protection of the user base, enabling barrier free interaction, in case of GameDAO for coordination and fundraising.

## Status

[x] create entity
[x] mutate xp, rep, trust
[ ] more granular access control
[ ] event subscription for on chain identity events
32 changes: 32 additions & 0 deletions sense/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Benchmarking setup for pallet-sense
use super::*;

#[allow(unused)]
use crate::Pallet as ZeroSense;
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, account};
use frame_system::RawOrigin;
use sp_std::vec;


benchmarks!{

create_entity {}: _(RawOrigin::Root, account("1", 0, 0), vec![1; 256])

mod_xp {
let caller_origin = <T as frame_system::Config>::Origin::from(RawOrigin::Root);
ZeroSense::<T>::create_entity(caller_origin, account("1", 0, 0), vec![1; 1])?;
}: _(RawOrigin::Root, account("1", 0, 0), 255)

mod_rep {
let caller_origin = <T as frame_system::Config>::Origin::from(RawOrigin::Root);
ZeroSense::<T>::create_entity(caller_origin, account("1", 0, 0), vec![1; 1])?;
}: _(RawOrigin::Root, account("1", 0, 0), 255)

mod_trust {
let caller_origin = <T as frame_system::Config>::Origin::from(RawOrigin::Root);
ZeroSense::<T>::create_entity(caller_origin, account("1", 0, 0), vec![1; 1])?;
}: _(RawOrigin::Root, account("1", 0, 0), 255)

}

impl_benchmark_test_suite!(ZeroSense, crate::mock::new_test_ext(), crate::mock::Test);
258 changes: 258 additions & 0 deletions sense/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
//
// _______________________________ ________
// \____ /\_ _____/\______ \\_____ \
// / / | __)_ | _/ / | \
// / /_ | \ | | \/ | \
// /_______ \/_______ / |____|_ /\_______ /
// \/ \/ \/ \/
// Z E R O . I O N E T W O R K
// © C O P Y R I O T 2 0 7 5 @ Z E R O . I O

// This file is part of ZERO Network.
// Copyright (C) 2010-2020 ZERO Labs.
// SPDX-License-Identifier: Apache-2.0

//! SENSE
//!
//! This pallet aggregates datapoints to reflect user experience and behaviour.
#![cfg_attr(not(feature = "std"), no_std)]

pub use weights::WeightInfo;
pub use pallet::*;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

pub mod weights;


#[frame_support::pallet]
pub mod pallet {
use frame_support::{dispatch::DispatchResult, pallet_prelude::*};
use frame_system::pallet_prelude::*;
use sp_std::vec::Vec;
use scale_info::TypeInfo;
use super::*;

pub const MAX_STRING_FIELD_LENGTH: usize = 256;

#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event> + Into<<Self as frame_system::Config>::Event>;
type ForceOrigin: EnsureOrigin<Self::Origin>;
type WeightInfo: WeightInfo;
}

#[derive(Encode, Decode, Default, PartialEq, Eq, TypeInfo)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Entity<AccountId, BlockNumber> {
account: AccountId,
index: u128,
cid: Vec<u8>,
created: BlockNumber,
mutated: BlockNumber,
}

#[derive(Encode, Decode, Default, PartialEq, Eq, TypeInfo)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct EntityProperty<BlockNumber> {
value: u64,
mutated: BlockNumber,
}

impl<AccountId, BlockNumber> Entity<AccountId, BlockNumber> {
pub fn new(account: AccountId, block_number: BlockNumber, index: u128, cid: Vec<u8>)
-> Entity<AccountId, BlockNumber> where BlockNumber: Clone, {
Entity {
account: account,
index: index,
cid: cid,
created: block_number.clone(),
mutated: block_number,
}
}
}

impl<BlockNumber> EntityProperty<BlockNumber> {
pub fn new(value: u64, block_number: BlockNumber)
-> EntityProperty<BlockNumber> {
EntityProperty {
value: value,
mutated: block_number,
}
}
}

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

#[pallet::storage]
#[pallet::getter(fn entity)]
pub(super) type Sense<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, Entity<T::AccountId,T::BlockNumber>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn xp)]
pub(super) type SenseXP<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, EntityProperty<T::BlockNumber>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn rep)]
pub(super) type SenseREP<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, EntityProperty<T::BlockNumber>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn trust)]
pub(super) type SenseTrust<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, EntityProperty<T::BlockNumber>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn nonce)]
pub type Nonce<T: Config> = StorageValue<_, u128, ValueQuery>;

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
EntityInit(T::AccountId, T::BlockNumber),
EntityMutateXP(T::AccountId, T::BlockNumber),
EntityMutateREP(T::AccountId, T::BlockNumber),
EntityMutateTrust(T::AccountId, T::BlockNumber),
}

// Errors inform users that something went wrong.
#[pallet::error]
pub enum Error<T> {
/// Entity Exists
EntityExists,
/// Entity Unknown
EntityUnknown,
/// Guru Meditation
GuruMeditation,
/// Param Limit Exceed
ParamLimitExceed,
/// Invalid Param
InvalidParam
}

#[pallet::call]
impl<T: Config> Pallet<T> {

#[pallet::weight(<T as Config>::WeightInfo::create_entity())]
pub fn create_entity(origin: OriginFor<T>, account: T::AccountId, cid: Vec<u8>) -> DispatchResult {

ensure_root(origin)?;
ensure!(cid.len() > 0, Error::<T>::InvalidParam);
ensure!(cid.len() <= MAX_STRING_FIELD_LENGTH, Error::<T>::ParamLimitExceed);
ensure!(!<Sense<T>>::contains_key(&account), Error::<T>::EntityExists);

let current_block = <frame_system::Pallet<T>>::block_number();
let index = <Nonce<T>>::get();

let entity = Entity::new(account.clone(), current_block, index, cid.clone());
let xp = EntityProperty { value: 0, mutated: current_block.clone() };
let rep = EntityProperty { value: 0, mutated: current_block.clone() };
let trust = EntityProperty { value: 0, mutated: current_block.clone() };

<SenseXP<T>>::insert( account.clone(), xp );
<SenseREP<T>>::insert( account.clone(), rep );
<SenseTrust<T>>::insert( account.clone(), trust );
<Sense<T>>::insert( account.clone(), entity );
// TODO: safe increment, checked_add
<Nonce<T>>::mutate(|n| *n += 1);

Self::deposit_event(
Event::EntityInit(account, current_block)
);
Ok(())

}

// TODO:
// mutation of values should be restricted
// certain roles are allowed to mutate values
// xp: realm
// rep: social
// trust: id
// all: governance
// sudo ( until its removal )

#[pallet::weight(<T as Config>::WeightInfo::mod_xp())]
pub fn mod_xp(origin: OriginFor<T>, account: T::AccountId, value: u8) -> DispatchResult {

ensure_root(origin)?;
ensure!( <Sense<T>>::contains_key(&account), Error::<T>::EntityUnknown );

let now = <frame_system::Pallet<T>>::block_number();
let v = u64::from(value);
let current = Self::xp(&account);

let updated = EntityProperty {
value: current.value.checked_add(v).ok_or(Error::<T>::GuruMeditation)?,
mutated: now.clone()
};

<SenseXP<T>>::insert( account.clone(), updated );

Self::deposit_event(
Event::EntityMutateXP(account, now)
);
Ok(())

}

#[pallet::weight(<T as Config>::WeightInfo::mod_rep())]
pub fn mod_rep(origin: OriginFor<T>, account: T::AccountId, value: u8) -> DispatchResult {

ensure_root(origin)?;
ensure!( <Sense<T>>::contains_key(&account), Error::<T>::EntityUnknown );

let now = <frame_system::Pallet<T>>::block_number();
let v = u64::from(value);
let current = Self::rep(&account);

let updated = EntityProperty {
value: current.value.checked_add(v).ok_or(Error::<T>::GuruMeditation)?,
mutated: now.clone()
};

<SenseREP<T>>::insert( account.clone(), updated );

Self::deposit_event(
Event::EntityMutateREP(account, now)
);
Ok(())

}

#[pallet::weight(<T as Config>::WeightInfo::mod_trust())]
pub fn mod_trust(origin: OriginFor<T>, account: T::AccountId, value: u8) -> DispatchResult {

ensure_root(origin)?;
ensure!( <Sense<T>>::contains_key(&account), Error::<T>::EntityUnknown );

let now = <frame_system::Pallet<T>>::block_number();
let v = u64::from(value);
let current = Self::trust(&account);

let updated = EntityProperty {
value: current.value.checked_add(v).ok_or(Error::<T>::GuruMeditation)?,
mutated: now
};

<SenseTrust<T>>::insert( account.clone(), updated );

Self::deposit_event(
Event::EntityMutateTrust(account, now)
);
Ok(())

}

// TODO:
// generic mod for all properties

}
}
Loading