content-directory-working-group.md 14 KB

Content Directory Working Group Module

Table of Contents

Name

ContentDirectoryWorkingGroup

Motivation

The working groups solves the problems of how to administrate the write access permissions to the content directory state.

Design

The working group has two types of participants. A lead, which is inducted by root. The lead is involved in two activities. First, hiring and managing the second participant type, namely curators. Second, creating and managing the actor groups, called permission groups, for the content directory. These groups are defined by some criteria for what accounts belong to them at any given time, and in particular they may defined to include the account(s) of one of the following

  • the led,
  • a specific curator
  • a specific member
  • a specific publisher
  • any curator
  • any member
  • any publisher.

These permission groups are presumed to be used with the permission module and the version store module. Both leads and curators are possibly staked and rewarded. The staking is managed by the staking module, and the rewards are managed by the recurring rewards module. All rewards in the group flow from a single group mint.

Usage

I used in concert with a range of other modules described in the next section.

Dependencies

  • RecurringReward module
  • Hiring module
  • Membership module
  • VersionedStorePermissions module

Concepts


trait Trait : RecurringReward::Trait + Hiring::Trait + Membership::Trait VersionedStorePermissions::Trait {

  // Type of identifier for permissions groups.
  type PermissionGroupId : INTEGER_TRAIT_CONSTRAINTS;

}

// Type of identifier for lead.
type LeadId = Trait::RoleActorId;

// Type of identifier for curators.
type CuratorId = Trait::RoleActorId;

// Type of identifier for publishers.
type PublisherId = Trait::MemberId;

enum LeadRoleState {
  Active,
  Exited {
    initiated_at_block_number: T::BlockNumber,
  }
}

// Working group lead: curator lead
// For now this role is not staked or inducted through an structured process, like the hiring module,
// hence information about this is missing. Recurring rewards is included, somewhat arbitrarily!
struct Lead<T: Trait> {

  // Account used to authenticate in this role,
  role_account: T::AccountId,

  // Whether the role has recurring reward, and if so an identifier for this.
  reward_relationship: Option<T::RewardRelationshipId>,

  // When was inducted
  // TODO: Add richer information about circumstances of induction
  inducted: T::BlockNumber,

  //
  stage: LeadRoleState

}

enum CuratorExitInitiationOrigin {
  Lead,
  Curator
}

enum CuratorRoleStage<T: Trait> {

  Active,

  Exited {

    origin: CuratorExitInitiationOrigin,

    initiated_at_block_number: T::BlockNumber,

    rationale_text: Vec<u8>

  }

}

struct CuratorInduction<T: Trait> {

  // Lead responsible
  lead: LeadId,

  // Application through which curator was inducted
  application: T::ApplicationId,

  // When induction occurred
  at_block: T::BlockNumber
}

// Working group participant: curator
// This role can be staked, have reward and be inducted through the hiring module.
struct Curator<T: Trait> {

  // Account used to authenticate in this role,
  role_account: T::AccountId,

  // Whether the role has recurring reward, and if so an identifier for this.
  reward_relationship: Option<T::RewardRelationshipId>,

  // Whether participant is staked, and if so, the identifier for this staking in the staking module.
  stake: Option<T::StakeId>,

  //
  stage: CuratorRoleStage<T>,

  //
  induction: CuratorInduction<T>
}

// The type of permission groups supported
enum PermissionGroupType<T: Trait> {

  CurrentLead,

  Curator(T::CuratorId),

  Member(T::MemberId),

  Publisher(T::PublisherId),

  AnyCurator,

  AnyMember,

  AnyPublisher
}

// Represents a group as understood by the VersionedStorePermissions module
struct PermissionGroup<T: Trait> {

  // ..
  type: PermissionGroupType<T>,

  // ..
  is_active: bool,

  // ..
  created: T::BlockNumber,

  // ..
  description: Vec<u8>
}

// Policy governing any curator opening which can be made by lead.
struct OpeningPolicy<T: Trait> {

 /**
  * // Whether there should be a number of active curators which would block the
  * // creation of new openings, and if so what value.
  * active_curator_count_blocking_new_openings: Option<u16>,
  */

  // Maximum length of review period of applications
  max_review_period_length: BlockNumber,

  // Staking policy for application
  application_staking_policy: Option<T::StakingPolicy>,

  // Staking policy for role itself
  role_staking_policy: Option<T::StakingPolicy>
}

State

  • mint: T::TokenMintId: The mint currently funding the rewards for this module.
  • current_lead: Option<T::LeadId>: The current lead.
  • leadById: linked_map T::LeadId => Lead<T>: Maps identifier to corresponding lead.
  • nextLeadId: T::LeadId: Next identifier for new current lead.
  • openings_policy: Option<OpeningPolicy<T>>: The constraints lead must respect when creating a new curator opening. Lack of policy is interpreted as blocking any new openings at all.
  • openings: linked_map T::OpeningId => (): set of identifiers for all openings originated from this group.
  • curatorById: linked_map T::CuratorId => Curator<T>: Maps identifier to corresponding curator.
  • nextCuratorId: T::CuratorId: Next identifier for new curator.
  • permissionGroupById: linked_map T::PermissionGroupId => PermissionGroup<T>: Maps identifier to corresponding permission group.
  • nextPermissionGroupId: T::PermissionGroupId: Next identifier for new permission group.
  • maxPermissionGroupDescriptionLength: u16: Upper bound for character length of description field of any new or updated PermissionGroup
  • maxCuratorExitRationaleTextLength: u16: Upper bound for character length of the rationale_text field of any new CuratorRoleStage.

Events

  • LeadSet
  • LeadUnset
  • OpeningPolicySet
  • LeadRewardUpdated
  • LeadRoleAccountUpdated
  • LeadRewardAccountUpdated
  • PermissionGroupAdded
  • PermissionGroupUpdated
  • CuratorOpeningAdded
  • AcceptedCuratorApplications
  • BeganCuratorApplicationReview
  • CuratorOpeningFilled
  • CuratorSlashed
  • TerminatedCurator
  • AppliedOnCuratorOpening
  • CuratorRewardUpdated
  • CuratorRoleAccountUpdated
  • CuratorRewardAccountUpdated
  • CuratorExited

Implemented Traits

Module implements VersionedStorePermissions::GroupMembershipChecker, and sets GroupMembershipChecker::GroupdId to T::PermissionGroupId.

Dispatchables

update_lead_role_account

Can only be called by Signed origin, and caller must pass test on membership module of key_can_sign_for_role for the current_lead.

Updates role_account of current_lead to given new value.

Emits LeadRoleAccountUpdated.

update_lead_reward_account

Can only be called by Signed origin, and caller must match role_account of set current_lead. Also, reward_relationship must be set on current_lead.

Updates account on reward_relationship to given new value.

Emits LeadRewardAccountUpdated.

add_permission_group

Can only be called by Signed origin, and caller must match role_account of set current_lead.

Creates and adds new permission group.

Emits PermissionGroupAdded.

update_permission_group

Can only be called by Signed origin, and caller must match role_account of set current_lead.

Updates a given permission group, based on its identifier. Field created is not mutable.

Emits PermissionGroupUpdated.

add_curator_opening

Can only be called by Signed origin, and caller must match role_account of set current_lead. Also requires that openings_policy is set, and if so, a new application is added to the Hiring module using relevant parameter values from this policy. The new opening identifier is added to openings.

Emits CuratorOpeningAdded.

accept_curator_applications

Can only be called by Signed origin, and caller must match role_account of set current_lead. Given opening identifier must be in openings. If so, begin_accepting_applications is called on the corresponding opening the Opening module.

Emits AcceptedCuratorApplications

begin_curator_applicant_review

Can only be called by Signed origin, and caller must match role_account of set current_lead. Given opening identifier must be in openings. If so, begin_review is called on the corresponding opening the Opening module.

Emits BeganCuratorApplicationReview

fill_curator_opening

Can only be called by Signed origin, and caller must match role_account of set current_lead. Given opening identifier must be in openings. Checks with the Membership module that all hires still can step into the role as curator at this time. If so, fill_opening is called on the corresponding opening the Opening module. All hired curators are turned into new Curator instances, with identifiers based on nextCuratorId, and added to curatorsById.

Emits CuratorOpeningFilled and CuratorAdded for each curator hired.

update_curator_reward

Can only be called by Signed origin, and caller must match role_account of set current_lead. Updates reward_relationship on given curator.

Emits CuratorRewardUpdated.

slash_curator

Can only be called by Signed origin, and caller must match role_account of set current_lead. Also requires that stake is set on given curator, if so, initiate_slashing is called on the Stake module on the stake for this curator.

Emits CuratorSlashed.

terminate_curator

Can only be called by Signed origin, and caller must match role_account of set current_lead. Also requires that given curator is found in curatorsById in the Active stage. If so, the stage is updated Exited, with suitable other parameters, and any reward_relationship set is disabled. Lastly, unstaking is initiated if present.

Emits TerminatedCurator.

apply_on_curator_opening

Can only be called by Signed origin, and caller must pass test on Membership module of whether they can occupy a curator role at this time. Next, provided parameters must match staking and other requirements of opening. If so, add_application is on Hiring module. Return value is returned.

Emits AppliedOnCuratorOpening.

update_curator_role_account

Can only be called by Signed origin, and account must match role_account of provided curator identifier. Also requires that given curator is found in curatorsById in the Active stage.

Updates role_account on given curator.

Emits CuratorRoleAccountUpdated.

update_curator_reward_account

Can only be called by Signed origin, and account must match role_account of provided curator identifier. Also requires that given curator is found in curatorsById in the Active stage. Also, given curator must also have reward_relationship set.

Updates account on given curator reward_relationship.

Emits CuratorRewardAccountUpdated.

exit_curator_role

Can only be called by Signed origin, and account must match role_account of provided curator identifier. Also requires that given curator is found in curatorsById in the Active stage. If so, the stage is updated Exited, with suitable other parameters, and any reward_relationship set is disabled. Lastly, unstaking is initiated if present.

Emits CuratorExited.

Non-dispatchable Methods

set_lead

Can only be called by Root origin, and requires that current_lead is not set. Membership module is consulted as to whether the given signing account can be setup as the curator lead with id nextLeadId, if no, then method terminates. Otherwise continues as follows.

A new recipient and reward relationship is added to the reward module, and a new current_lead instance is created with corresponding values and id nextLeadId, added to leadById undert this id, and current_lead i also set to this key. Lastly, nextLeadId is incremented.

Emits event LeadSet. Returns nothing.

unset_lead

Can only be called by Root origin, and requires that current_lead is set. Membership module is informed to unregister the lead as playing the role of a curator lead. If reward_relationship is set on lead, then disable it to any further rewards. Lastly set exited to the current block number.

Emits event LeadUnset. Returns nothing.

set_opening_policy

Can only be called by Root origin. Updates opening_policy.

Emits event OpeningPolicySet. Returns nothing.

update_lead_reward

Can only be called by Root origin, and requires that current_lead is set. The lead must also have reward_relationship set. If so, then amount_per_payout, next_payment_in_block and payout_interval of the reward relationship can be updated.

Emits event LeadRewardUpdated. Returns nothing.

account_is_in_group

Takes group id and looks up permissionGroupById, lack of match results in false being returned. A match is then used to evaluate the given account as follows

  • CurrentLead: Account matches role_account of current_lead which is set.
  • Curator(id): ..
  • Member(id): ..
  • Publisher(id): .
  • AnyCurator: ..
  • AnyMember: ..
  • AnyPublisher: ..