// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use frame_support::derive_impl; use frame_system::pallet_prelude::BlockNumberFor; use sp_core::{sr25519, ConstU64}; use sp_runtime::{ generic, traits::{BlakeTwo256, Verify}, }; #[frame_support::pallet] mod module { use super::*; use frame_support::pallet_prelude::*; pub type Request = (::AccountId, Role, BlockNumberFor); pub type Requests = Vec>; #[derive(Copy, Clone, Eq, PartialEq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub enum Role { Storage, } #[derive(Copy, Clone, Eq, PartialEq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct RoleParameters { // minimum actors to maintain - if role is unstaking // and remaining actors would be less that this value - prevent or punish for unstaking pub min_actors: u32, // the maximum number of spots available to fill for a role pub max_actors: u32, // payouts are made at this block interval pub reward_period: BlockNumberFor, // minimum amount of time before being able to unstake pub bonding_period: BlockNumberFor, // how long tokens remain locked for after unstaking pub unbonding_period: BlockNumberFor, // minimum period required to be in service. unbonding before this time is highly penalized pub min_service_period: BlockNumberFor, // "startup" time allowed for roles that need to sync their infrastructure // with other providers before they are considered in service and punishable for // not delivering required level of service. pub startup_grace_period: BlockNumberFor, } impl Default for RoleParameters { fn default() -> Self { Self { max_actors: 10, reward_period: BlockNumberFor::::default(), unbonding_period: BlockNumberFor::::default(), // not currently used min_actors: 5, bonding_period: BlockNumberFor::::default(), min_service_period: BlockNumberFor::::default(), startup_grace_period: BlockNumberFor::::default(), } } } #[pallet::pallet] pub struct Pallet(_); #[pallet::config] pub trait Config: frame_system::Config + TypeInfo {} #[pallet::call] impl Pallet {} /// requirements to enter and maintain status in roles #[pallet::storage] #[pallet::getter(fn parameters)] pub type Parameters = StorageMap<_, Blake2_128Concat, Role, RoleParameters, OptionQuery>; /// the roles members can enter into #[pallet::storage] #[pallet::getter(fn available_roles)] #[pallet::unbounded] pub type AvailableRoles = StorageValue<_, Vec, ValueQuery>; /// Actors list #[pallet::storage] #[pallet::getter(fn actor_account_ids)] #[pallet::unbounded] pub type ActorAccountIds = StorageValue<_, Vec>; /// actor accounts associated with a role #[pallet::storage] #[pallet::getter(fn account_ids_by_role)] #[pallet::unbounded] pub type AccountIdsByRole = StorageMap<_, Blake2_128Concat, Role, Vec>; /// tokens locked until given block number #[pallet::storage] #[pallet::getter(fn bondage)] pub type Bondage = StorageMap<_, Blake2_128Concat, T::AccountId, BlockNumberFor>; /// First step before enter a role is registering intent with a new account/key. /// This is done by sending a role_entry_request() from the new account. /// The member must then send a stake() transaction to approve the request and enter the desired /// role. The account making the request will be bonded and must have /// sufficient balance to cover the minimum stake for the role. /// Bonding only occurs after successful entry into a role. #[pallet::storage] #[pallet::getter(fn role_entry_requests)] #[pallet::unbounded] pub type RoleEntryRequests = StorageValue<_, Requests>; /// Entry request expires after this number of blocks #[pallet::storage] #[pallet::getter(fn request_life_time)] pub type RequestLifeTime = StorageValue<_, u64, ValueQuery, ConstU64<0>>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { pub enable_storage_role: bool, pub request_life_time: u64, #[serde(skip)] pub _config: sp_std::marker::PhantomData, } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { if self.enable_storage_role { >::insert(Role::Storage, >::default()); >::put(vec![Role::Storage]); } >::put(self.request_life_time); } } } pub type BlockNumber = u64; pub type Signature = sr25519::Signature; pub type AccountId = ::Signer; pub type Header = generic::Header; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; type BlockHashCount = ConstU64<10>; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; type OnSetCode = (); } impl module::Config for Runtime {} frame_support::construct_runtime!( pub enum Runtime { System: frame_system, Module: module, } ); #[test] fn create_genesis_config() { let config = RuntimeGenesisConfig { system: Default::default(), module: module::GenesisConfig { request_life_time: 0, enable_storage_role: true, ..Default::default() }, }; assert_eq!(config.module.request_life_time, 0); assert!(config.module.enable_storage_role); }