diff --git a/pallets/cess-treasury/README.md b/pallets/cess-treasury/README.md new file mode 100755 index 00000000..8c5140e5 --- /dev/null +++ b/pallets/cess-treasury/README.md @@ -0,0 +1,98 @@ +# Cess Treasury Module + +Manage meta information of cess-treasury. + +## Overview + +There are three accounts in the CESS treasury that store funds for different purposes. At the same time, in order to adjust the inflation rate of network tokens, this module provides corresponding methods for destroying funds. Users with root authority can control the funds of two of the accounts, and the reward pool of the storage node does not have any authority to operate. + +## Terminology + +* **PunishTreasuryId:** Used to collect tokens that have been punished by storage nodes. The tokens in their accounts can be controlled by root privileges. + +* **SpaceTreasuryId:** Used to collect tokens spent by users to purchase space. This account can control funds with root authority. + +* **MinerRewardId:** Collect tokens used to reward storage nodes. Each era is issued tokens to the account by the `staking pallet`. Root privileges do not have the right to control the account's token. + +## Extrinsic + +* `send_funds_to_pid()` - Can be called with any permissions. Send any number of tokens to **PunishTreasuryId** account. +* `send_funds_to_sid()` - Can be called with any permissions. Send any number of tokens to **SpaceTreasuryId** account. +* `pid_burn_funds()` - Can only be called with root privileges. Destroy any number of tokens in the **PunishTreasuryId** account. +* `sid_burn_funds()` - Can only be called with root privileges. Destroy any number of tokens in the **SpaceTreasuryId** account. +* `pid_send_funds()` Can only be called with root privileges. **PunishTreasuryId** account transfers any number of tokens to the designated account. +* `sid_send_funds()` Can only be called with root privileges. **SpaceTreasuryId** account transfers any number of tokens to the designated account. + +## Interface + +### RewardPool + +The interface used to operate the reward account and perform addition, modification and check on the funds in the reward account. However, it cannot directly manipulate the balance and can only record changes to `CurrencyReward`. + +#### Function + +* `get_reward()` - Get the current reward amount. +* `get_reward_128()` - Get the current u128 type reward amount. +* `add_reward()` - Increase reward amount. It should be noted that the total amount of rewards must remain unchanged and can only be used in some special circumstances and cannot be directly increased. Otherwise, the amount of bonus pool rewards and the balance in the account will not correspond. +* `sub_reward()` - Reduce reward amount. + +#### Usage + +in pallet::Config + +```rust +pub trait Config: frame_system::Config + sp_std::fmt::Debug { + // ... + type RewardPool: RewardPool, BalanceOf>; + // ... +} +``` + +in runtime.rs +```rust +impl pallet_sminer::Config for Runtime { + // ... + type RewardPool = CessTreasury; + // ... +} +``` + +### TreasuryHandle + +Provides an interface for collecting tokens, through which other pallets transfer tokens to designated accounts. + +#### Function + +* `send_to_pid()` - Send any number of tokens to **PunishTreasuryId**. +* `send_to_sid()` - Send any number of tokens to **SpaceTreasuryId**. + +#### Usage + +in pallet::Config + +```rust +pub trait Config: frame_system::Config + sp_std::fmt::Debug { + // ... + type CessTreasuryHandle: TreasuryHandle, BalanceOf>; + // ... +} +``` + +in runtime.rs +```rust +impl pallet_sminer::Config for Runtime { + // ... + type CessTreasuryHandle = CessTreasury; + // ... +} +``` + +## Implementation Details + +### Miner Reward + +The total issuance of storage node rewards in the first year is 477,000,000 CESS, with an average of 326,488 CESS per era (One era every six hours). +Starting in the second year, the annual reward decreases linearly with an annual decay rate of approximately 0.841, halving every 4 years. For details, please view the CESS Network’s [Reward Mechanism](https://docs.cess.cloud/core/storage-miner/reward). + +* **MinerRewardId:** The wallet account of the miner reward pool, in which balance is the real bonus. +* **CurrencyReward:** It is a `StorageValue` type storage pool. The current reward records how many available rewards are available in the bonus account. Change it by issuing rewards each time, or recycling rewards. diff --git a/pallets/cess-treasury/src/README.md b/pallets/cess-treasury/src/README.md deleted file mode 100644 index 029dc980..00000000 --- a/pallets/cess-treasury/src/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Cess Treasury Module - -Manage meta information of cess-treasury. - -## Terminology - -## Extrinsic - - -## Interface - -### TeeWorkerHandler - - -#### Usage - - -## Implementation Details - -### diff --git a/pallets/file-bank/src/lib.rs b/pallets/file-bank/src/lib.rs index b483ec18..b9474fd2 100755 --- a/pallets/file-bank/src/lib.rs +++ b/pallets/file-bank/src/lib.rs @@ -18,11 +18,11 @@ //! * `buyfile` - Buy file with download fee. #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(test)] -mod mock; +// #[cfg(test)] +// mod mock; -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod tests; use frame_support::traits::{ FindAuthor, Randomness, @@ -673,6 +673,7 @@ pub mod pallet { &sender, idle_sig_info.accumulator, idle_sig_info.front, + idle_sig_info.rear, tee_sig, )?; @@ -753,6 +754,7 @@ pub mod pallet { let idle_space = T::MinerControl::add_miner_idle_space( &sender, idle_sig_info.accumulator, + idle_sig_info.front, idle_sig_info.rear, tee_sig, )?; @@ -1131,4 +1133,4 @@ impl BlockNumberProvider for Pallet { fn current_block_number() -> Self::BlockNumber { >::block_number() } -} +} \ No newline at end of file diff --git a/pallets/file-bank/src/mock.rs b/pallets/file-bank/src/mock.rs index 102751d0..1bd965db 100755 --- a/pallets/file-bank/src/mock.rs +++ b/pallets/file-bank/src/mock.rs @@ -1,494 +1,494 @@ -// This file is part of Substrate. - -// Copyright (C) 2020-2021 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. - -//! Test utilities - -use super::*; -use crate as file_bank; -use frame_support::{ - parameter_types, - weights::Weight, - traits::{ConstU32, EqualPrivilegeOnly, OneSessionHandler}, -}; -use frame_system::{EnsureRoot}; -use sp_core::{H256, sr25519::Signature}; -use sp_runtime::{ - testing::{Header, TestXt, UintAuthorityId}, - traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentityLookup, IdentifyAccount, Verify}, - Perbill, -}; -use frame_support_test::TestRandomness; -use frame_benchmarking::account; -use pallet_cess_staking::{StashOf, Exposure, ExposureOf}; -use frame_election_provider_support::{ - onchain, SequentialPhragmen, VoteWeight, -}; -use sp_staking::{ - EraIndex, SessionIndex, -}; -use std::{ - cell::RefCell, - convert::TryFrom, -}; -use cp_scheduler_credit::SchedulerStashAccountFinder; -/// The AccountId alias in this test module. -pub(crate) type AccountId = <::Signer as IdentifyAccount>::AccountId; -type BlockNumber = u64; -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; -type Balance = u64; - -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - Balances: pallet_balances, - FileBank: file_bank, - Sminer: pallet_sminer, - Scheduler: pallet_scheduler, - Timestamp: pallet_timestamp, - Staking: pallet_cess_staking, - Session: pallet_session, - Historical: pallet_session::historical, - BagsList: pallet_bags_list, - TeeWorker: pallet_tee_worker, - SchedulerCredit: pallet_scheduler_credit, - Oss: pallet_oss, - Preimage: pallet_preimage - } -); - -impl pallet_oss::Config for Test { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); -} - -parameter_types! { - #[derive(Clone, PartialEq, Eq)] - pub const StringLimit: u32 = 100; - #[derive(Clone, PartialEq, Eq)] - pub const OneHours: u32 = 60 * 10; - #[derive(Clone, PartialEq, Eq)] - pub const OneDay: u32 = 60 * 10 * 24; -} - -parameter_types! { - pub const MinimumPeriod: u64 = 1; -} - -impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; -} - -impl pallet_scheduler::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type MaxScheduledPerBlock = (); - type WeightInfo = (); - type Preimages = Preimage; -} - -parameter_types! { - pub const RewardPalletId: PalletId = PalletId(*b"sminerpt"); - pub const MultipleFines: u8 = 7; - pub const DepositBufferPeriod: u32 = 3; - pub const ItemLimit: u32 = 1024; - pub const MaxAward: u128 = 1_306_849_000_000_000_000; - pub const LockInPeriod: u8 = 2; -} - -impl pallet_sminer::Config for Test { - type Currency = Balances; - // The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type PalletId = RewardPalletId; - type SScheduler = Scheduler; - type AScheduler = Scheduler; - type SPalletsOrigin = OriginCaller; - type SProposal = RuntimeCall; - type WeightInfo = (); - type ItemLimit = ItemLimit; - type MultipleFines = MultipleFines; - type DepositBufferPeriod = DepositBufferPeriod; - type OneDayBlock = OneDay; - type MaxAward = MaxAward; - type LockInPeriod = LockInPeriod; -} - -parameter_types! { - pub const TeeWorkerPalletId: PalletId = PalletId(*b"filmpdpt"); - #[derive(Clone, PartialEq, Eq)] - pub const SchedulerMaximum: u32 = 10000; - #[derive(Clone, PartialEq, Eq)] - pub const ParamsLimit: u32 = 359; -} - -impl pallet_tee_worker::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type TeeWorkerPalletId = TeeWorkerPalletId; - type StringLimit = StringLimit; - type WeightInfo = (); - type CreditCounter = SchedulerCredit; - type SchedulerMaximum = SchedulerMaximum; - type ParamsLimit = ParamsLimit; -} - -const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = - [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; - -parameter_types! { - pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; - pub static MaxNominations: u32 = 16; -} - -impl pallet_bags_list::Config for Test { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type ScoreProvider = Staking; - type BagThresholds = BagThresholds; - type Score = VoteWeight; -} - -parameter_types! { - pub static SessionsPerEra: SessionIndex = 3; - pub static SlashDeferDuration: EraIndex = 0; - pub static Period: BlockNumber = 5; - pub static Offset: BlockNumber = 0; -} - -sp_runtime::impl_opaque_keys! { - pub struct SessionKeys { - pub other: OtherSessionHandler, - } -} -impl pallet_session::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = AccountId; - type ValidatorIdOf = StashOf; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type SessionHandler = (OtherSessionHandler, ); - type Keys = SessionKeys; - type WeightInfo = (); -} - -impl pallet_session::historical::Config for Test { - type FullIdentification = Exposure; - type FullIdentificationOf = ExposureOf; -} - -thread_local! { - pub static REWARD_REMAINDER_UNBALANCED: RefCell = RefCell::new(0); -} - -pub struct OnChainSeqPhragmen; - -impl onchain::Config for OnChainSeqPhragmen { - type System = Test; - type Solver = SequentialPhragmen; - type DataProvider = Staking; - type WeightInfo = (); - type MaxWinners = ConstU32<100>; - type VotersBound = ConstU32<{ u32::MAX }>; - type TargetsBound = ConstU32<{ u32::MAX }>; -} - -impl pallet_cess_staking::Config for Test { - const ERAS_PER_YEAR: u64 = 8766; - const FIRST_YEAR_VALIDATOR_REWARDS: BalanceOf = 618_000_000; - const FIRST_YEAR_SMINER_REWARDS: BalanceOf = 309_000_000; - const REWARD_DECREASE_RATIO: Perbill = Perbill::from_perthousand(794); - type SminerRewardPool = (); - type Currency = Balances; - type CurrencyBalance = ::Balance; - type UnixTime = Timestamp; - type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type ElectionProvider = onchain::OnChainExecution; - type GenesisElectionProvider = Self::ElectionProvider; - type MaxNominations = MaxNominations; - type RewardRemainder = (); - type RuntimeEvent = RuntimeEvent; - type Slash = (); - type Reward = (); - type SessionsPerEra = (); - type BondingDuration = (); - type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; - type SessionInterface = Self; - type EraPayout = (); - type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; - type OffendingValidatorsThreshold = (); - type VoterList = BagsList; - type TargetList = pallet_cess_staking::UseValidatorsMap; - type MaxUnlockingChunks = ConstU32<32>; - type HistoryDepth = ConstU32<84>; - type OnStakerSlash = (); - type BenchmarkingConfig = pallet_cess_staking::TestBenchmarkingConfig; - type WeightInfo = (); -} - -pub type Extrinsic = TestXt; - -impl frame_system::offchain::SendTransactionTypes for Test - where - RuntimeCall: From, -{ - type Extrinsic = Extrinsic; - type OverarchingCall = RuntimeCall; -} - -pub struct ExtBuilder; - -impl Default for ExtBuilder { - fn default() -> Self { - Self {} - } -} - -pub struct OtherSessionHandler; - -impl OneSessionHandler for OtherSessionHandler { - type Key = UintAuthorityId; - - fn on_genesis_session<'a, I: 'a>(_: I) - where - I: Iterator, - AccountId: 'a, - {} - - fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) - where - I: Iterator, - AccountId: 'a, - {} - - fn on_disabled(_validator_index: u32) {} -} - -impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { - type Public = UintAuthorityId; -} - -// impl ExtBuilder { -// #[warn(dead_code)] -// fn build(self) -> sp_io::TestExternalities { -// let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); -// let ext = sp_io::TestExternalities::from(storage); -// ext +// // This file is part of Substrate. + +// // Copyright (C) 2020-2021 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. + +// //! Test utilities + +// use super::*; +// use crate as file_bank; +// use frame_support::{ +// parameter_types, +// weights::Weight, +// traits::{ConstU32, EqualPrivilegeOnly, OneSessionHandler}, +// }; +// use frame_system::{EnsureRoot}; +// use sp_core::{H256, sr25519::Signature}; +// use sp_runtime::{ +// testing::{Header, TestXt, UintAuthorityId}, +// traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentityLookup, IdentifyAccount, Verify}, +// Perbill, +// }; +// use frame_support_test::TestRandomness; +// use frame_benchmarking::account; +// use pallet_cess_staking::{StashOf, Exposure, ExposureOf}; +// use frame_election_provider_support::{ +// onchain, SequentialPhragmen, VoteWeight, +// }; +// use sp_staking::{ +// EraIndex, SessionIndex, +// }; +// use std::{ +// cell::RefCell, +// convert::TryFrom, +// }; +// use cp_scheduler_credit::SchedulerStashAccountFinder; +// /// The AccountId alias in this test module. +// pub(crate) type AccountId = <::Signer as IdentifyAccount>::AccountId; +// type BlockNumber = u64; +// type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +// type Block = frame_system::mocking::MockBlock; +// type Balance = u64; + +// frame_support::construct_runtime!( +// pub enum Test where +// Block = Block, +// NodeBlock = Block, +// UncheckedExtrinsic = UncheckedExtrinsic, +// { +// System: frame_system, +// Balances: pallet_balances, +// FileBank: file_bank, +// Sminer: pallet_sminer, +// Scheduler: pallet_scheduler, +// Timestamp: pallet_timestamp, +// Staking: pallet_cess_staking, +// Session: pallet_session, +// Historical: pallet_session::historical, +// BagsList: pallet_bags_list, +// TeeWorker: pallet_tee_worker, +// SchedulerCredit: pallet_scheduler_credit, +// Oss: pallet_oss, +// Preimage: pallet_preimage +// } +// ); + +// impl pallet_oss::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type WeightInfo = (); +// } + +// parameter_types! { +// #[derive(Clone, PartialEq, Eq)] +// pub const StringLimit: u32 = 100; +// #[derive(Clone, PartialEq, Eq)] +// pub const OneHours: u32 = 60 * 10; +// #[derive(Clone, PartialEq, Eq)] +// pub const OneDay: u32 = 60 * 10 * 24; +// } + +// parameter_types! { +// pub const MinimumPeriod: u64 = 1; +// } + +// impl pallet_timestamp::Config for Test { +// type Moment = u64; +// type OnTimestampSet = (); +// type MinimumPeriod = MinimumPeriod; +// type WeightInfo = (); +// } + +// parameter_types! { +// pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +// } + +// impl pallet_scheduler::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type RuntimeOrigin = RuntimeOrigin; +// type PalletsOrigin = OriginCaller; +// type RuntimeCall = RuntimeCall; +// type MaximumWeight = MaximumSchedulerWeight; +// type ScheduleOrigin = EnsureRoot; +// type OriginPrivilegeCmp = EqualPrivilegeOnly; +// type MaxScheduledPerBlock = (); +// type WeightInfo = (); +// type Preimages = Preimage; +// } + +// parameter_types! { +// pub const RewardPalletId: PalletId = PalletId(*b"sminerpt"); +// pub const MultipleFines: u8 = 7; +// pub const DepositBufferPeriod: u32 = 3; +// pub const ItemLimit: u32 = 1024; +// pub const MaxAward: u128 = 1_306_849_000_000_000_000; +// pub const LockInPeriod: u8 = 2; +// } + +// impl pallet_sminer::Config for Test { +// type Currency = Balances; +// // The ubiquitous event type. +// type RuntimeEvent = RuntimeEvent; +// type PalletId = RewardPalletId; +// type SScheduler = Scheduler; +// type AScheduler = Scheduler; +// type SPalletsOrigin = OriginCaller; +// type SProposal = RuntimeCall; +// type WeightInfo = (); +// type ItemLimit = ItemLimit; +// type MultipleFines = MultipleFines; +// type DepositBufferPeriod = DepositBufferPeriod; +// type OneDayBlock = OneDay; +// type MaxAward = MaxAward; +// type LockInPeriod = LockInPeriod; +// } + +// parameter_types! { +// pub const TeeWorkerPalletId: PalletId = PalletId(*b"filmpdpt"); +// #[derive(Clone, PartialEq, Eq)] +// pub const SchedulerMaximum: u32 = 10000; +// #[derive(Clone, PartialEq, Eq)] +// pub const ParamsLimit: u32 = 359; +// } + +// impl pallet_tee_worker::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type Currency = Balances; +// type TeeWorkerPalletId = TeeWorkerPalletId; +// type StringLimit = StringLimit; +// type WeightInfo = (); +// type CreditCounter = SchedulerCredit; +// type SchedulerMaximum = SchedulerMaximum; +// type ParamsLimit = ParamsLimit; +// } + +// const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = +// [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + +// parameter_types! { +// pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; +// pub static MaxNominations: u32 = 16; +// } + +// impl pallet_bags_list::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type WeightInfo = (); +// type ScoreProvider = Staking; +// type BagThresholds = BagThresholds; +// type Score = VoteWeight; +// } + +// parameter_types! { +// pub static SessionsPerEra: SessionIndex = 3; +// pub static SlashDeferDuration: EraIndex = 0; +// pub static Period: BlockNumber = 5; +// pub static Offset: BlockNumber = 0; +// } + +// sp_runtime::impl_opaque_keys! { +// pub struct SessionKeys { +// pub other: OtherSessionHandler, +// } +// } +// impl pallet_session::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type ValidatorId = AccountId; +// type ValidatorIdOf = StashOf; +// type ShouldEndSession = pallet_session::PeriodicSessions; +// type NextSessionRotation = pallet_session::PeriodicSessions; +// type SessionManager = pallet_session::historical::NoteHistoricalRoot; +// type SessionHandler = (OtherSessionHandler, ); +// type Keys = SessionKeys; +// type WeightInfo = (); +// } + +// impl pallet_session::historical::Config for Test { +// type FullIdentification = Exposure; +// type FullIdentificationOf = ExposureOf; +// } + +// thread_local! { +// pub static REWARD_REMAINDER_UNBALANCED: RefCell = RefCell::new(0); +// } + +// pub struct OnChainSeqPhragmen; + +// impl onchain::Config for OnChainSeqPhragmen { +// type System = Test; +// type Solver = SequentialPhragmen; +// type DataProvider = Staking; +// type WeightInfo = (); +// type MaxWinners = ConstU32<100>; +// type VotersBound = ConstU32<{ u32::MAX }>; +// type TargetsBound = ConstU32<{ u32::MAX }>; +// } + +// impl pallet_cess_staking::Config for Test { +// const ERAS_PER_YEAR: u64 = 8766; +// const FIRST_YEAR_VALIDATOR_REWARDS: BalanceOf = 618_000_000; +// const FIRST_YEAR_SMINER_REWARDS: BalanceOf = 309_000_000; +// const REWARD_DECREASE_RATIO: Perbill = Perbill::from_perthousand(794); +// type SminerRewardPool = (); +// type Currency = Balances; +// type CurrencyBalance = ::Balance; +// type UnixTime = Timestamp; +// type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; +// type ElectionProvider = onchain::OnChainExecution; +// type GenesisElectionProvider = Self::ElectionProvider; +// type MaxNominations = MaxNominations; +// type RewardRemainder = (); +// type RuntimeEvent = RuntimeEvent; +// type Slash = (); +// type Reward = (); +// type SessionsPerEra = (); +// type BondingDuration = (); +// type SlashDeferDuration = (); +// type SlashCancelOrigin = frame_system::EnsureRoot; +// type SessionInterface = Self; +// type EraPayout = (); +// type NextNewSession = (); +// type MaxNominatorRewardedPerValidator = ConstU32<64>; +// type OffendingValidatorsThreshold = (); +// type VoterList = BagsList; +// type TargetList = pallet_cess_staking::UseValidatorsMap; +// type MaxUnlockingChunks = ConstU32<32>; +// type HistoryDepth = ConstU32<84>; +// type OnStakerSlash = (); +// type BenchmarkingConfig = pallet_cess_staking::TestBenchmarkingConfig; +// type WeightInfo = (); +// } + +// pub type Extrinsic = TestXt; + +// impl frame_system::offchain::SendTransactionTypes for Test +// where +// RuntimeCall: From, +// { +// type Extrinsic = Extrinsic; +// type OverarchingCall = RuntimeCall; +// } + +// pub struct ExtBuilder; + +// impl Default for ExtBuilder { +// fn default() -> Self { +// Self {} // } -// #[warn(dead_code)] -// pub fn build_and_execute(self, test: impl FnOnce() -> ()) { -// self.build().execute_with(test); +// } + +// pub struct OtherSessionHandler; + +// impl OneSessionHandler for OtherSessionHandler { +// type Key = UintAuthorityId; + +// fn on_genesis_session<'a, I: 'a>(_: I) +// where +// I: Iterator, +// AccountId: 'a, +// {} + +// fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) +// where +// I: Iterator, +// AccountId: 'a, +// {} + +// fn on_disabled(_validator_index: u32) {} +// } + +// impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { +// type Public = UintAuthorityId; +// } + +// // impl ExtBuilder { +// // #[warn(dead_code)] +// // fn build(self) -> sp_io::TestExternalities { +// // let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); +// // let ext = sp_io::TestExternalities::from(storage); +// // ext +// // } +// // #[warn(dead_code)] +// // pub fn build_and_execute(self, test: impl FnOnce() -> ()) { +// // self.build().execute_with(test); +// // } +// // } + +// impl frame_system::offchain::SigningTypes for Test { +// type Public = ::Signer; +// type Signature = Signature; +// } + +// impl frame_system::offchain::CreateSignedTransaction for Test +// where +// RuntimeCall: From, +// { +// fn create_transaction>( +// call: RuntimeCall, +// _public: ::Signer, +// _account: AccountId, +// nonce: u64, +// ) -> Option<(RuntimeCall, ::SignaturePayload)> { +// Some((call, (nonce, ()))) // } // } -impl frame_system::offchain::SigningTypes for Test { - type Public = ::Signer; - type Signature = Signature; -} - -impl frame_system::offchain::CreateSignedTransaction for Test - where - RuntimeCall: From, -{ - fn create_transaction>( - call: RuntimeCall, - _public: ::Signer, - _account: AccountId, - nonce: u64, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { - Some((call, (nonce, ()))) - } -} - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_parts(1024)); -} - -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -pub struct MockStashAccountFinder(PhantomData); - -impl SchedulerStashAccountFinder -for MockStashAccountFinder -{ - fn find_stash_account_id(ctrl_account_id: &AccountId) -> Option { - Some(ctrl_account_id.clone()) - } -} - -parameter_types! { - pub const PeriodDuration: BlockNumber = 64_000; -} -impl pallet_scheduler_credit::Config for Test { - type StashAccountFinder = MockStashAccountFinder; - type PeriodDuration = PeriodDuration; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 1; -} - -impl pallet_balances::Config for Test { - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; -} - -impl pallet_preimage::Config for Test { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = (); - type ManagerOrigin = EnsureRoot; - type BaseDeposit = (); - type ByteDeposit = (); -} - -parameter_types! { - pub const FilbakPalletId: PalletId = PalletId(*b"filebank"); - #[derive(Clone, Eq, PartialEq)] - pub const InvalidLimit: u32 = 100000; - #[derive(Clone, Eq, PartialEq)] - pub const BucketLimit: u32 = 1000; - #[derive(Clone, Eq, PartialEq)] - pub const NameStrLimit: u32 = 63; - #[derive(Clone, Eq, PartialEq)] - pub const MinLength: u32 = 3; - #[derive(Clone, Eq, PartialEq)] - pub const FileListLimit: u32 = 500000; - #[derive(Clone, Eq, PartialEq)] - pub const FrozenDays: BlockNumber = 60 * 10 * 24 * 7; -} - -impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type WeightInfo = (); - type RuntimeCall = RuntimeCall; - type FindAuthor = (); - type CreditCounter = SchedulerCredit; - type Scheduler = pallet_tee_worker::Pallet::; - type MinerControl = pallet_sminer::Pallet::; - type MyRandomness = TestRandomness; - type FilbakPalletId = FilbakPalletId; - type StringLimit = StringLimit; - type OneDay = OneDay; - type FileListLimit = FileListLimit; - type NameStrLimit = NameStrLimit; - type BucketLimit = BucketLimit; - type OssFindAuthor = Oss; - type FrozenDays = FrozenDays; - type InvalidLimit = InvalidLimit; - type MinLength = MinLength; -} - -pub fn account1() -> AccountId { - account("account1", 0, 0) -} - -pub fn account2() -> AccountId { - account("account2", 0, 0) -} - -pub fn miner1() -> AccountId { - account("miner1", 0, 0) -} - -pub fn stash1() -> AccountId { - account("stash1", 0, 0) -} - -pub fn controller1() -> AccountId { - account("controller1", 0, 0) -} - -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (account1(), 18_000_000_000_000_000_000), - (account2(), 1_000_000_000_000), - (miner1(), 1_000_000_000_000), - (stash1(), 1_000_000_000_000), - (controller1(), 1_000_000_000_000), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - file_bank::GenesisConfig:: { - price: 30 - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| { - System::set_block_number(1); //must set block_number, otherwise the deposit_event() don't work - }); - ext -} +// parameter_types! { +// pub const BlockHashCount: u64 = 250; +// pub BlockWeights: frame_system::limits::BlockWeights = +// frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_parts(1024)); +// } + +// impl frame_system::Config for Test { +// type BaseCallFilter = frame_support::traits::Everything; +// type BlockWeights = (); +// type BlockLength = (); +// type RuntimeOrigin = RuntimeOrigin; +// type RuntimeCall = RuntimeCall; +// type Index = u64; +// type BlockNumber = u64; +// type Hash = H256; +// type Hashing = BlakeTwo256; +// type AccountId = AccountId; +// type Lookup = IdentityLookup; +// type Header = Header; +// type RuntimeEvent = RuntimeEvent; +// type BlockHashCount = BlockHashCount; +// type DbWeight = (); +// type Version = (); +// type PalletInfo = PalletInfo; +// type AccountData = pallet_balances::AccountData; +// type OnNewAccount = (); +// type OnKilledAccount = (); +// type SystemWeightInfo = (); +// type SS58Prefix = (); +// type OnSetCode = (); +// type MaxConsumers = ConstU32<16>; +// } + +// pub struct MockStashAccountFinder(PhantomData); + +// impl SchedulerStashAccountFinder +// for MockStashAccountFinder +// { +// fn find_stash_account_id(ctrl_account_id: &AccountId) -> Option { +// Some(ctrl_account_id.clone()) +// } +// } + +// parameter_types! { +// pub const PeriodDuration: BlockNumber = 64_000; +// } +// impl pallet_scheduler_credit::Config for Test { +// type StashAccountFinder = MockStashAccountFinder; +// type PeriodDuration = PeriodDuration; +// } + +// parameter_types! { +// pub const ExistentialDeposit: u64 = 1; +// } + +// impl pallet_balances::Config for Test { +// type Balance = u64; +// type DustRemoval = (); +// type RuntimeEvent = RuntimeEvent; +// type ExistentialDeposit = ExistentialDeposit; +// type AccountStore = System; +// type WeightInfo = (); +// type MaxLocks = (); +// type MaxReserves = (); +// type ReserveIdentifier = [u8; 8]; +// } + +// impl pallet_preimage::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type WeightInfo = (); +// type Currency = (); +// type ManagerOrigin = EnsureRoot; +// type BaseDeposit = (); +// type ByteDeposit = (); +// } + +// parameter_types! { +// pub const FilbakPalletId: PalletId = PalletId(*b"filebank"); +// #[derive(Clone, Eq, PartialEq)] +// pub const InvalidLimit: u32 = 100000; +// #[derive(Clone, Eq, PartialEq)] +// pub const BucketLimit: u32 = 1000; +// #[derive(Clone, Eq, PartialEq)] +// pub const NameStrLimit: u32 = 63; +// #[derive(Clone, Eq, PartialEq)] +// pub const MinLength: u32 = 3; +// #[derive(Clone, Eq, PartialEq)] +// pub const FileListLimit: u32 = 500000; +// #[derive(Clone, Eq, PartialEq)] +// pub const FrozenDays: BlockNumber = 60 * 10 * 24 * 7; +// } + +// impl Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type Currency = Balances; +// type WeightInfo = (); +// type RuntimeCall = RuntimeCall; +// type FindAuthor = (); +// type CreditCounter = SchedulerCredit; +// type Scheduler = pallet_tee_worker::Pallet::; +// type MinerControl = pallet_sminer::Pallet::; +// type MyRandomness = TestRandomness; +// type FilbakPalletId = FilbakPalletId; +// type StringLimit = StringLimit; +// type OneDay = OneDay; +// type FileListLimit = FileListLimit; +// type NameStrLimit = NameStrLimit; +// type BucketLimit = BucketLimit; +// type OssFindAuthor = Oss; +// type FrozenDays = FrozenDays; +// type InvalidLimit = InvalidLimit; +// type MinLength = MinLength; +// } + +// pub fn account1() -> AccountId { +// account("account1", 0, 0) +// } + +// pub fn account2() -> AccountId { +// account("account2", 0, 0) +// } + +// pub fn miner1() -> AccountId { +// account("miner1", 0, 0) +// } + +// pub fn stash1() -> AccountId { +// account("stash1", 0, 0) +// } + +// pub fn controller1() -> AccountId { +// account("controller1", 0, 0) +// } + +// pub fn new_test_ext() -> sp_io::TestExternalities { +// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); +// pallet_balances::GenesisConfig:: { +// balances: vec![ +// (account1(), 18_000_000_000_000_000_000), +// (account2(), 1_000_000_000_000), +// (miner1(), 1_000_000_000_000), +// (stash1(), 1_000_000_000_000), +// (controller1(), 1_000_000_000_000), +// ], +// } +// .assimilate_storage(&mut t) +// .unwrap(); +// file_bank::GenesisConfig:: { +// price: 30 +// } +// .assimilate_storage(&mut t) +// .unwrap(); +// let mut ext = sp_io::TestExternalities::new(t); +// ext.execute_with(|| { +// System::set_block_number(1); //must set block_number, otherwise the deposit_event() don't work +// }); +// ext +// } diff --git a/pallets/file-bank/src/tests.rs b/pallets/file-bank/src/tests.rs index 2930dc9b..079145ae 100755 --- a/pallets/file-bank/src/tests.rs +++ b/pallets/file-bank/src/tests.rs @@ -1,501 +1,501 @@ -//! This file is part of CESS. -//! -//! Tests for the module. - -use super::*; -use crate::{mock::*, Event}; -use mock::System as Sys; -use frame_support::{assert_ok, assert_noop}; -use cp_cess_common::{IpAddress, Hash}; -use pallet_sminer::MinerControl; - - -#[derive(Debug, Clone)] -pub struct MockingFileBankInfo { - file_hash: Hash, - file_size: u64, - slice_info: Vec>, -} - -type Balance = u64; -const UNIT_PRICE: Balance = 30; - -impl Default for MockingFileBankInfo { - fn default() -> Self { - let file_hash = Hash([5u8; 64]); - let mut file_hash1: Vec = file_hash.0.to_vec(); - file_hash1.append("-001".as_bytes().to_vec().as_mut()); - let file_hash1: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); - - let mut file_hash2: Vec = file_hash.0.to_vec(); - file_hash2.append("-002".as_bytes().to_vec().as_mut()); - let file_hash2: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); - - let mut file_hash3: Vec = file_hash.0.to_vec(); - file_hash3.append("-002".as_bytes().to_vec().as_mut()); - let file_hash3: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); - MockingFileBankInfo { - file_hash: file_hash, - file_size: 12, - slice_info: vec![SliceInfo::{ - miner_id: 1, - shard_size: 111, - block_num: 8, - shard_id: file_hash1, - miner_ip: IpAddress::IPV4([127,0,0,1], 15000), - miner_acc: mock::miner1(), - }, - SliceInfo::{ - miner_id: 1, - shard_size: 111, - block_num: 8, - shard_id: file_hash2, - miner_ip: IpAddress::IPV4([127,0,0,1], 15000), - miner_acc: mock::miner1(), - }, - SliceInfo::{ - miner_id: 1, - shard_size: 111, - block_num: 8, - shard_id: file_hash3, - miner_ip: IpAddress::IPV4([127,0,0,1], 15000), - miner_acc: mock::miner1(), - }, - ] - } - } -} - -fn upload_declaration_alias(account: AccountId, file_name: Vec, file_hash: Hash, bucket_name: Vec) -> DispatchResult { - let user_brief = UserBrief::{ - user: account.clone(), - file_name: file_name.try_into().unwrap(), - bucket_name: bucket_name.try_into().unwrap(), - }; - FileBank::upload_declaration( - RuntimeOrigin::signed(account.clone()), - file_hash, - user_brief, - ) -} - -fn upload_file_alias(_account: AccountId, controller: AccountId, file_info: &MockingFileBankInfo) -> DispatchResult { - let MockingFileBankInfo { file_hash, file_size, slice_info} = file_info.clone(); - FileBank::upload( - RuntimeOrigin::signed(controller), - file_hash, - file_size, - slice_info, - ) -} - -fn create_new_bucket(acc: AccountId, bucket_name: Vec) -> DispatchResult { - FileBank::create_bucket( - RuntimeOrigin::signed(acc.clone()), - acc, - bucket_name.try_into().unwrap(), - ) -} - -fn register_scheduler(stash: AccountId, controller: AccountId) -> DispatchResult { - pallet_cess_staking::Bonded::::insert(&stash, controller.clone()); - TeeWorker::registration_scheduler( - RuntimeOrigin::signed(controller), - stash, - IpAddress::IPV4([127,0,0,1], 15000), - ) - -} - -fn register_miner(miner: AccountId) -> DispatchResult { - Sminer::regnstk( - RuntimeOrigin::signed(miner), - miner.clone(), - IpAddress::IPV4([127,0,0,1], 15000), - 2_000u128.try_into().unwrap(), - ) -} - -fn add_power_for_miner(controller: AccountId, miner: AccountId) -> DispatchResult { - let max: u8 = 10; - let mut filler_list: Vec> = Vec::new(); - for i in 0 .. max { - let filler_hash: Hash = Hash([i; 64]); - filler_list.push( - FillerInfo:: { - index: 1, - filler_size: 8 * 1_048_576, - block_num: 8, - segment_size: 1_048_576, - scan_size: 1_048_576, - miner_address: miner.clone(), - filler_hash: filler_hash.clone(), - } - ) - } - FileBank::upload_filler(RuntimeOrigin::signed(controller), miner, filler_list)?; - - Ok(()) -} - -#[test] -fn buy_space_works() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let _bal_before = Balances::free_balance(acc1); - let miner1 = mock::miner1(); - let space_gb = 10_u128; - let bn = Sys::block_number(); - - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB - - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 10)); - - let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(space_gb * 1024 * 1_048_576, uhsd.total_space); // MB unit - assert_eq!(14400 * 30 + bn as u128, uhsd.deadline as u128); - - assert_eq!(uhsd.total_space, uhsd.remaining_space); - let price = UNIT_PRICE * space_gb as u64; - - let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; - assert_eq!(mock::RuntimeEvent::from(Event::BuySpace { acc: acc1, storage_capacity: space_gb * 1024 * 1_048_576, spend: price }), event); - }); -} - -#[test] -fn expansion_space_work() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let miner1 = mock::miner1(); - let space_gb = 1000_u128; - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB - - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 1)); - let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(1 * 1024 * 1_048_576, uhsd.total_space); // MB unit - - assert_ok!(FileBank::expansion_space(RuntimeOrigin::signed(acc1), 1)); - let price = UNIT_PRICE * 1; - - let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; - assert_eq!(mock::RuntimeEvent::from(Event::ExpansionSpace { acc: acc1, expansion_space: 1024 * 1024 * 1024, fee: price,}), event); - - let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); // MB unit - }); -} - -#[test] -fn renewal_space_work() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let miner1 = mock::miner1(); - let space_gb = 1000_u128; - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB - - let gib_count = 2; - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), gib_count)); - let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); // MB unit - - let renewal_days = 32; - let price = UNIT_PRICE / 30 * (renewal_days as u64) * (gib_count as u64); - - assert_ok!(FileBank::renewal_space(RuntimeOrigin::signed(acc1), renewal_days)); - let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; - assert_eq!(mock::RuntimeEvent::from(Event::RenewalSpace { acc: acc1, renewal_days, fee: price}), event); - - let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); - assert_eq!(1, uhsd.start); - assert_eq!(62 * 14400 + 1, uhsd.deadline); - }); -} - -#[test] -fn upload_declaration() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let file_name = "cess-book".as_bytes().to_vec(); - let file_hash = Hash([5u8; 64]); - let bucket_name: Vec = "cess-bucket".as_bytes().to_vec(); - - assert_noop!(upload_declaration_alias(acc1.clone(), file_name.clone(), file_hash.clone(), bucket_name.clone()), Error::::NonExistent); - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - - assert_ok!(upload_declaration_alias(acc1, file_name, file_hash, bucket_name)); - }); -} - -#[test] -fn upload_works() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let miner1 = mock::miner1(); - let stash1 = mock::stash1(); - let controller1 = mock::controller1(); - let mfi = MockingFileBankInfo::default(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - let file_name = "cess-book".as_bytes().to_vec(); - - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, file_name.clone(), mfi.file_hash.clone(), bucket_name.clone())); - assert_noop!(upload_file_alias(acc1, controller1, &mfi), Error::::ScheduleNonExistent); - assert_ok!(register_miner(miner1)); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - //upload() file not work have not buy space - - - let space_gb = 20_u128; - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - assert_ok!(add_power_for_miner(controller1, miner1)); - - assert_ok!(upload_file_alias(acc1, controller1, &mfi)); - - let file_hash = mfi.file_hash; - let file_size = mfi.file_size; - let file_slice_info = UserFileSliceInfo{ - file_hash: file_hash.clone(), - file_size: file_size, - }; - assert!(File::::contains_key(&file_hash)); - let t = UserOwnedSpace::::try_get(acc1).unwrap(); - assert_eq!(mfi.file_size as u128, t.used_space); - assert_eq!(t.total_space - mfi.file_size as u128, t.remaining_space); - assert!(UserHoldFileList::::try_get(acc1).unwrap().contains(&file_slice_info)); - - let event = Sys::events().pop().expect("Expected at least one FileUpload to be found").event; - assert_eq!(mock::RuntimeEvent::from(Event::FileUpload { acc: controller1 }), event); - }); -} - -#[test] -fn upload_should_not_work_when_insufficient_storage() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - let mut mfi = MockingFileBankInfo::default(); - let space_gb = 20_u128; - let bucket_name = "cess-bucket".as_bytes().to_vec(); - assert_ok!(register_miner(miner1)); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - assert_ok!(add_power_for_miner(controller1, miner1)); - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - mfi.file_size = 3 * 1024 * 1024 * 1024; // large file - - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name.clone())); - assert_noop!(upload_file_alias(acc1.clone(), controller1.clone(), &mfi), Error::::InsufficientStorage); - - if let Err(e) = upload_file_alias(acc1, controller1, &mfi) { - if let DispatchError::Module(m) = e { - assert_eq!("InsufficientStorage", m.message.unwrap()); - } - } - }) -} - -#[test] -fn delete_file_works() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - let mfi = MockingFileBankInfo::default(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - assert_noop!(FileBank::delete_file(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), mfi.file_hash.clone()), Error::::FileNonExistent); - - let space_gb = 20_u128; - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - // acc1 upload file - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name.clone())); - assert_ok!(add_power_for_miner(controller1, miner1)); - assert_ok!(upload_file_alias(acc1, controller1, &mfi)); - assert_noop!(FileBank::delete_file(RuntimeOrigin::signed(mock::account2()), mock::account2(), mfi.file_hash.clone()), Error::::NotOwner); - let ss_before = UserOwnedSpace::::try_get(acc1).unwrap(); - - assert_ok!(FileBank::delete_file(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), mfi.file_hash.clone())); - - let ss_after = UserOwnedSpace::::try_get(acc1).unwrap(); - assert!(!File::::contains_key(&mfi.file_hash)); - assert_ne!(ss_before.remaining_space, ss_after.remaining_space); - - let event = Sys::events().pop().expect("Expected at least one DeleteFile to be found").event; - assert_eq!(mock::RuntimeEvent::from(Event::DeleteFile { operator: acc1.clone(), owner: acc1.clone(), file_hash: mfi.file_hash }), event); - }); -} - -#[test] -fn upload_filler_work() { - new_test_ext().execute_with(|| { - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - assert_noop!(add_power_for_miner(controller1.clone(), miner1.clone()), Error::::ScheduleNonExistent); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - assert_noop!(add_power_for_miner(controller1.clone(), miner1.clone()), pallet_sminer::Error::::NotMiner); - assert_ok!(register_miner(miner1)); - assert_ok!(add_power_for_miner(controller1.clone(), miner1.clone())); - - let (power, _) = Sminer::get_power_and_space(miner1.clone()).unwrap(); - assert_eq!(1_048_576 * 8 * 10, power); - }); -} - -#[test] -fn clear_invalid_file_work() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - let mfi = MockingFileBankInfo::default(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name)); - assert_ok!(add_power_for_miner(controller1, miner1)); - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - assert_ok!(upload_file_alias(acc1, controller1, &mfi)); - - let mut file_hash_list = InvalidFile::::get(miner1.clone()); - assert_ok!(FileBank::clear_invalid_file(RuntimeOrigin::signed(miner1.clone()), file_hash_list[0])); - file_hash_list.remove(0); - assert_eq!(file_hash_list, InvalidFile::::get(miner1.clone())); - }); -} - -#[test] -fn create_bucket_works() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - let bound_bucket_name: BoundedVec = bucket_name.try_into().unwrap(); - assert_ok!(FileBank::create_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); - let bucket = Bucket::::get(&acc1, bound_bucket_name).unwrap(); - assert_eq!(bucket.authority.len(), 1); - assert_eq!(bucket.authority[0], acc1); - }); -} - -#[test] -fn delete_bucket_works() { - new_test_ext().execute_with(|| { - let acc1 = mock::account1(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - let bound_bucket_name: BoundedVec = bucket_name.try_into().unwrap(); - assert_ok!(FileBank::create_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); - assert!(>::contains_key(&acc1, bound_bucket_name.clone())); - - assert_ok!(FileBank::delete_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); - assert!(!>::contains_key(&acc1, bound_bucket_name.clone())); - }); -} - -#[test] -fn transfer_ownership_works() { - new_test_ext().execute_with(|| { - let acc1 = account1(); - let acc2 = account2(); - let mfi = MockingFileBankInfo::default(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - let bound_bucket_name: BoundedVec = bucket_name.clone().try_into().unwrap(); - - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - assert_ok!(add_power_for_miner(controller1, miner1)); - - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc2), 2)); - - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(create_new_bucket(acc2.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash.clone(), bucket_name.clone())); - assert_ok!(upload_file_alias(acc1, controller1, &mfi)); - - let file = >::get(&mfi.file_hash).unwrap(); - assert_eq!(file.user_brief_list[0].user, acc1.clone()); - - let target_brief = UserBrief:: { - user: acc2.clone(), - file_name: "test-file2".as_bytes().to_vec().try_into().unwrap(), - bucket_name: bound_bucket_name.clone(), - }; - - assert_ok!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name, target_brief, mfi.file_hash.clone())); - - let file = >::get(&mfi.file_hash).unwrap(); - assert_eq!(file.user_brief_list[0].user, acc2.clone()); - assert!(!FileBank::check_is_file_owner(&acc1, &mfi.file_hash)); - }) -} - -#[test] -fn transfer_ownership_exception() { - new_test_ext().execute_with(|| { - let acc1 = account1(); - let acc2 = account2(); - let mfi = MockingFileBankInfo::default(); - let bucket_name = "cess-bucket".as_bytes().to_vec(); - let bound_bucket_name: BoundedVec = bucket_name.clone().try_into().unwrap(); - - let stash1 = mock::stash1(); - let miner1 = mock::miner1(); - let controller1 = mock::controller1(); - - assert_ok!(register_miner(miner1.clone())); - assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); - assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); - assert_ok!(add_power_for_miner(controller1, miner1)); - - assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); - - assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); - assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash.clone(), bucket_name.clone())); - assert_ok!(upload_file_alias(acc1, controller1, &mfi)); - - let target_brief = UserBrief:: { - user: acc2.clone(), - file_name: "test-file2".as_bytes().to_vec().try_into().unwrap(), - bucket_name: bound_bucket_name.clone(), - }; - - assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc2.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NotOwner); - let file_hash = Hash([8u8; 64]); - assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), file_hash.clone()), Error::::FileNonExistent); - assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NonExistent); - - assert_ok!(create_new_bucket(acc2.clone(), bucket_name.clone())); - assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NotPurchasedSpace); - }) -} +// //! This file is part of CESS. +// //! +// //! Tests for the module. + +// use super::*; +// use crate::{mock::*, Event}; +// use mock::System as Sys; +// use frame_support::{assert_ok, assert_noop}; +// use cp_cess_common::{IpAddress, Hash}; +// use pallet_sminer::MinerControl; + + +// #[derive(Debug, Clone)] +// pub struct MockingFileBankInfo { +// file_hash: Hash, +// file_size: u64, +// slice_info: Vec>, +// } + +// type Balance = u64; +// const UNIT_PRICE: Balance = 30; + +// impl Default for MockingFileBankInfo { +// fn default() -> Self { +// let file_hash = Hash([5u8; 64]); +// let mut file_hash1: Vec = file_hash.0.to_vec(); +// file_hash1.append("-001".as_bytes().to_vec().as_mut()); +// let file_hash1: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); + +// let mut file_hash2: Vec = file_hash.0.to_vec(); +// file_hash2.append("-002".as_bytes().to_vec().as_mut()); +// let file_hash2: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); + +// let mut file_hash3: Vec = file_hash.0.to_vec(); +// file_hash3.append("-002".as_bytes().to_vec().as_mut()); +// let file_hash3: [u8; 68] = file_hash1.as_slice().try_into().unwrap(); +// MockingFileBankInfo { +// file_hash: file_hash, +// file_size: 12, +// slice_info: vec![SliceInfo::{ +// miner_id: 1, +// shard_size: 111, +// block_num: 8, +// shard_id: file_hash1, +// miner_ip: IpAddress::IPV4([127,0,0,1], 15000), +// miner_acc: mock::miner1(), +// }, +// SliceInfo::{ +// miner_id: 1, +// shard_size: 111, +// block_num: 8, +// shard_id: file_hash2, +// miner_ip: IpAddress::IPV4([127,0,0,1], 15000), +// miner_acc: mock::miner1(), +// }, +// SliceInfo::{ +// miner_id: 1, +// shard_size: 111, +// block_num: 8, +// shard_id: file_hash3, +// miner_ip: IpAddress::IPV4([127,0,0,1], 15000), +// miner_acc: mock::miner1(), +// }, +// ] +// } +// } +// } + +// fn upload_declaration_alias(account: AccountId, file_name: Vec, file_hash: Hash, bucket_name: Vec) -> DispatchResult { +// let user_brief = UserBrief::{ +// user: account.clone(), +// file_name: file_name.try_into().unwrap(), +// bucket_name: bucket_name.try_into().unwrap(), +// }; +// FileBank::upload_declaration( +// RuntimeOrigin::signed(account.clone()), +// file_hash, +// user_brief, +// ) +// } + +// fn upload_file_alias(_account: AccountId, controller: AccountId, file_info: &MockingFileBankInfo) -> DispatchResult { +// let MockingFileBankInfo { file_hash, file_size, slice_info} = file_info.clone(); +// FileBank::upload( +// RuntimeOrigin::signed(controller), +// file_hash, +// file_size, +// slice_info, +// ) +// } + +// fn create_new_bucket(acc: AccountId, bucket_name: Vec) -> DispatchResult { +// FileBank::create_bucket( +// RuntimeOrigin::signed(acc.clone()), +// acc, +// bucket_name.try_into().unwrap(), +// ) +// } + +// fn register_scheduler(stash: AccountId, controller: AccountId) -> DispatchResult { +// pallet_cess_staking::Bonded::::insert(&stash, controller.clone()); +// TeeWorker::registration_scheduler( +// RuntimeOrigin::signed(controller), +// stash, +// IpAddress::IPV4([127,0,0,1], 15000), +// ) + +// } + +// fn register_miner(miner: AccountId) -> DispatchResult { +// Sminer::regnstk( +// RuntimeOrigin::signed(miner), +// miner.clone(), +// IpAddress::IPV4([127,0,0,1], 15000), +// 2_000u128.try_into().unwrap(), +// ) +// } + +// fn add_power_for_miner(controller: AccountId, miner: AccountId) -> DispatchResult { +// let max: u8 = 10; +// let mut filler_list: Vec> = Vec::new(); +// for i in 0 .. max { +// let filler_hash: Hash = Hash([i; 64]); +// filler_list.push( +// FillerInfo:: { +// index: 1, +// filler_size: 8 * 1_048_576, +// block_num: 8, +// segment_size: 1_048_576, +// scan_size: 1_048_576, +// miner_address: miner.clone(), +// filler_hash: filler_hash.clone(), +// } +// ) +// } +// FileBank::upload_filler(RuntimeOrigin::signed(controller), miner, filler_list)?; + +// Ok(()) +// } + +// #[test] +// fn buy_space_works() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let _bal_before = Balances::free_balance(acc1); +// let miner1 = mock::miner1(); +// let space_gb = 10_u128; +// let bn = Sys::block_number(); + +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB + +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 10)); + +// let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(space_gb * 1024 * 1_048_576, uhsd.total_space); // MB unit +// assert_eq!(14400 * 30 + bn as u128, uhsd.deadline as u128); + +// assert_eq!(uhsd.total_space, uhsd.remaining_space); +// let price = UNIT_PRICE * space_gb as u64; + +// let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; +// assert_eq!(mock::RuntimeEvent::from(Event::BuySpace { acc: acc1, storage_capacity: space_gb * 1024 * 1_048_576, spend: price }), event); +// }); +// } + +// #[test] +// fn expansion_space_work() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let miner1 = mock::miner1(); +// let space_gb = 1000_u128; +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB + +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 1)); +// let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(1 * 1024 * 1_048_576, uhsd.total_space); // MB unit + +// assert_ok!(FileBank::expansion_space(RuntimeOrigin::signed(acc1), 1)); +// let price = UNIT_PRICE * 1; + +// let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; +// assert_eq!(mock::RuntimeEvent::from(Event::ExpansionSpace { acc: acc1, expansion_space: 1024 * 1024 * 1024, fee: price,}), event); + +// let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); // MB unit +// }); +// } + +// #[test] +// fn renewal_space_work() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let miner1 = mock::miner1(); +// let space_gb = 1000_u128; +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); // GB => MB + +// let gib_count = 2; +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), gib_count)); +// let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); // MB unit + +// let renewal_days = 32; +// let price = UNIT_PRICE / 30 * (renewal_days as u64) * (gib_count as u64); + +// assert_ok!(FileBank::renewal_space(RuntimeOrigin::signed(acc1), renewal_days)); +// let event = Sys::events().pop().expect("Expected at least one BuySpace to be found").event; +// assert_eq!(mock::RuntimeEvent::from(Event::RenewalSpace { acc: acc1, renewal_days, fee: price}), event); + +// let uhsd = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(2 * 1024 * 1_048_576, uhsd.total_space); +// assert_eq!(1, uhsd.start); +// assert_eq!(62 * 14400 + 1, uhsd.deadline); +// }); +// } + +// #[test] +// fn upload_declaration() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let file_name = "cess-book".as_bytes().to_vec(); +// let file_hash = Hash([5u8; 64]); +// let bucket_name: Vec = "cess-bucket".as_bytes().to_vec(); + +// assert_noop!(upload_declaration_alias(acc1.clone(), file_name.clone(), file_hash.clone(), bucket_name.clone()), Error::::NonExistent); +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); + +// assert_ok!(upload_declaration_alias(acc1, file_name, file_hash, bucket_name)); +// }); +// } + +// #[test] +// fn upload_works() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let miner1 = mock::miner1(); +// let stash1 = mock::stash1(); +// let controller1 = mock::controller1(); +// let mfi = MockingFileBankInfo::default(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// let file_name = "cess-book".as_bytes().to_vec(); + +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, file_name.clone(), mfi.file_hash.clone(), bucket_name.clone())); +// assert_noop!(upload_file_alias(acc1, controller1, &mfi), Error::::ScheduleNonExistent); +// assert_ok!(register_miner(miner1)); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// //upload() file not work have not buy space + + +// let space_gb = 20_u128; +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); +// assert_ok!(add_power_for_miner(controller1, miner1)); + +// assert_ok!(upload_file_alias(acc1, controller1, &mfi)); + +// let file_hash = mfi.file_hash; +// let file_size = mfi.file_size; +// let file_slice_info = UserFileSliceInfo{ +// file_hash: file_hash.clone(), +// file_size: file_size, +// }; +// assert!(File::::contains_key(&file_hash)); +// let t = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert_eq!(mfi.file_size as u128, t.used_space); +// assert_eq!(t.total_space - mfi.file_size as u128, t.remaining_space); +// assert!(UserHoldFileList::::try_get(acc1).unwrap().contains(&file_slice_info)); + +// let event = Sys::events().pop().expect("Expected at least one FileUpload to be found").event; +// assert_eq!(mock::RuntimeEvent::from(Event::FileUpload { acc: controller1 }), event); +// }); +// } + +// #[test] +// fn upload_should_not_work_when_insufficient_storage() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); +// let mut mfi = MockingFileBankInfo::default(); +// let space_gb = 20_u128; +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// assert_ok!(register_miner(miner1)); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// assert_ok!(add_power_for_miner(controller1, miner1)); +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); +// mfi.file_size = 3 * 1024 * 1024 * 1024; // large file + +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name.clone())); +// assert_noop!(upload_file_alias(acc1.clone(), controller1.clone(), &mfi), Error::::InsufficientStorage); + +// if let Err(e) = upload_file_alias(acc1, controller1, &mfi) { +// if let DispatchError::Module(m) = e { +// assert_eq!("InsufficientStorage", m.message.unwrap()); +// } +// } +// }) +// } + +// #[test] +// fn delete_file_works() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); +// let mfi = MockingFileBankInfo::default(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// assert_noop!(FileBank::delete_file(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), mfi.file_hash.clone()), Error::::FileNonExistent); + +// let space_gb = 20_u128; +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1, 1_048_576 * 1024 * space_gb)); +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); +// // acc1 upload file +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name.clone())); +// assert_ok!(add_power_for_miner(controller1, miner1)); +// assert_ok!(upload_file_alias(acc1, controller1, &mfi)); +// assert_noop!(FileBank::delete_file(RuntimeOrigin::signed(mock::account2()), mock::account2(), mfi.file_hash.clone()), Error::::NotOwner); +// let ss_before = UserOwnedSpace::::try_get(acc1).unwrap(); + +// assert_ok!(FileBank::delete_file(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), mfi.file_hash.clone())); + +// let ss_after = UserOwnedSpace::::try_get(acc1).unwrap(); +// assert!(!File::::contains_key(&mfi.file_hash)); +// assert_ne!(ss_before.remaining_space, ss_after.remaining_space); + +// let event = Sys::events().pop().expect("Expected at least one DeleteFile to be found").event; +// assert_eq!(mock::RuntimeEvent::from(Event::DeleteFile { operator: acc1.clone(), owner: acc1.clone(), file_hash: mfi.file_hash }), event); +// }); +// } + // #[test] -// fn update_price_works() { +// fn upload_filler_work() { +// new_test_ext().execute_with(|| { +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); +// assert_noop!(add_power_for_miner(controller1.clone(), miner1.clone()), Error::::ScheduleNonExistent); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// assert_noop!(add_power_for_miner(controller1.clone(), miner1.clone()), pallet_sminer::Error::::NotMiner); +// assert_ok!(register_miner(miner1)); +// assert_ok!(add_power_for_miner(controller1.clone(), miner1.clone())); + +// let (power, _) = Sminer::get_power_and_space(miner1.clone()).unwrap(); +// assert_eq!(1_048_576 * 8 * 10, power); +// }); +// } + +// #[test] +// fn clear_invalid_file_work() { // new_test_ext().execute_with(|| { // let acc1 = mock::account1(); -// assert_ok!(FileBank::update_price(Origin::signed(acc1), Vec::from("1000"))); -// assert_eq!(1000 / 3, UnitPrice::::try_get().unwrap()); +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); +// let mfi = MockingFileBankInfo::default(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); + +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); + +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash, bucket_name)); +// assert_ok!(add_power_for_miner(controller1, miner1)); +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); +// assert_ok!(upload_file_alias(acc1, controller1, &mfi)); + +// let mut file_hash_list = InvalidFile::::get(miner1.clone()); +// assert_ok!(FileBank::clear_invalid_file(RuntimeOrigin::signed(miner1.clone()), file_hash_list[0])); +// file_hash_list.remove(0); +// assert_eq!(file_hash_list, InvalidFile::::get(miner1.clone())); // }); // } + +// #[test] +// fn create_bucket_works() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// let bound_bucket_name: BoundedVec = bucket_name.try_into().unwrap(); +// assert_ok!(FileBank::create_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); +// let bucket = Bucket::::get(&acc1, bound_bucket_name).unwrap(); +// assert_eq!(bucket.authority.len(), 1); +// assert_eq!(bucket.authority[0], acc1); +// }); +// } + +// #[test] +// fn delete_bucket_works() { +// new_test_ext().execute_with(|| { +// let acc1 = mock::account1(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// let bound_bucket_name: BoundedVec = bucket_name.try_into().unwrap(); +// assert_ok!(FileBank::create_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); +// assert!(>::contains_key(&acc1, bound_bucket_name.clone())); + +// assert_ok!(FileBank::delete_bucket(RuntimeOrigin::signed(acc1.clone()), acc1.clone(), bound_bucket_name.clone())); +// assert!(!>::contains_key(&acc1, bound_bucket_name.clone())); +// }); +// } + +// #[test] +// fn transfer_ownership_works() { +// new_test_ext().execute_with(|| { +// let acc1 = account1(); +// let acc2 = account2(); +// let mfi = MockingFileBankInfo::default(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// let bound_bucket_name: BoundedVec = bucket_name.clone().try_into().unwrap(); + +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); + +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// assert_ok!(add_power_for_miner(controller1, miner1)); + +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc2), 2)); + +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(create_new_bucket(acc2.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash.clone(), bucket_name.clone())); +// assert_ok!(upload_file_alias(acc1, controller1, &mfi)); + +// let file = >::get(&mfi.file_hash).unwrap(); +// assert_eq!(file.user_brief_list[0].user, acc1.clone()); + +// let target_brief = UserBrief:: { +// user: acc2.clone(), +// file_name: "test-file2".as_bytes().to_vec().try_into().unwrap(), +// bucket_name: bound_bucket_name.clone(), +// }; + +// assert_ok!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name, target_brief, mfi.file_hash.clone())); + +// let file = >::get(&mfi.file_hash).unwrap(); +// assert_eq!(file.user_brief_list[0].user, acc2.clone()); +// assert!(!FileBank::check_is_file_owner(&acc1, &mfi.file_hash)); +// }) +// } + +// #[test] +// fn transfer_ownership_exception() { +// new_test_ext().execute_with(|| { +// let acc1 = account1(); +// let acc2 = account2(); +// let mfi = MockingFileBankInfo::default(); +// let bucket_name = "cess-bucket".as_bytes().to_vec(); +// let bound_bucket_name: BoundedVec = bucket_name.clone().try_into().unwrap(); + +// let stash1 = mock::stash1(); +// let miner1 = mock::miner1(); +// let controller1 = mock::controller1(); + +// assert_ok!(register_miner(miner1.clone())); +// assert_ok!(Sminer::add_power(&miner1 ,1_048_576 * 1024 * 20)); +// assert_ok!(register_scheduler(stash1.clone(), controller1.clone())); +// assert_ok!(add_power_for_miner(controller1, miner1)); + +// assert_ok!(FileBank::buy_space(RuntimeOrigin::signed(acc1), 2)); + +// assert_ok!(create_new_bucket(acc1.clone(), bucket_name.clone())); +// assert_ok!(upload_declaration_alias(acc1, "cess-book".as_bytes().to_vec(), mfi.file_hash.clone(), bucket_name.clone())); +// assert_ok!(upload_file_alias(acc1, controller1, &mfi)); + +// let target_brief = UserBrief:: { +// user: acc2.clone(), +// file_name: "test-file2".as_bytes().to_vec().try_into().unwrap(), +// bucket_name: bound_bucket_name.clone(), +// }; + +// assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc2.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NotOwner); +// let file_hash = Hash([8u8; 64]); +// assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), file_hash.clone()), Error::::FileNonExistent); +// assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NonExistent); + +// assert_ok!(create_new_bucket(acc2.clone(), bucket_name.clone())); +// assert_noop!(FileBank::ownership_transfer(RuntimeOrigin::signed(acc1.clone()), bound_bucket_name.clone(), target_brief.clone(), mfi.file_hash.clone()), Error::::NotPurchasedSpace); +// }) +// } +// // #[test] +// // fn update_price_works() { +// // new_test_ext().execute_with(|| { +// // let acc1 = mock::account1(); +// // assert_ok!(FileBank::update_price(Origin::signed(acc1), Vec::from("1000"))); +// // assert_eq!(1000 / 3, UnitPrice::::try_get().unwrap()); +// // }); +// // } diff --git a/pallets/oss/README.md b/pallets/oss/README.md new file mode 100755 index 00000000..c785992e --- /dev/null +++ b/pallets/oss/README.md @@ -0,0 +1,63 @@ +# Oss Module + +Manage meta information of DeOss. + +## Overview + +DeOss is a server used to upload and download files in the cess network. Process files uploaded by users, distribute them to storage nodes, and put the meta information of the files on the chain. + +If you want to make your DeOss public and provide services to others, you need to register in this module and make your information public on the network. + +## Terminology + +### Authorize Operator + +In the CESS network, if users want to upload their own files through DeOss, they need to authorize the designated DeOss account. + +After authorization, DeOss will have the authority to perform the following operations for the user: + +* Upload Files. +* Delete Files. +* Create Bucket. +* Delete Bucket. + +Currently, it supports authorizing multiple DeOss to provide services to users. + +## Extrinsic + +* `authorize()` - User authorization DeOss function. +* `cancel_authorize()` - The user cancels the function of authorizing a certain DeOss. +* `register()` - DeOss registration function, after registration, users across the entire network will be able to access the service through the endpoint or peer id provided by DeOss. +* `update()` - DeOss updates the current endpoint or peer id information. +* `destroy()` - DeOss logout function. + +## Interface + +### OssFindAuthor + +Interface provided to other modules for detecting permissions + +#### Function + +* `is_authorized` - Determine whether the user has authorized the DeOss. + +#### Usage + +in pallet::Config + +```rust +pub trait Config: frame_system::Config + sp_std::fmt::Debug { + // ... + type OssFindAuthor: OssFindAuthor; + // ... +} +``` + +in runtime.rs +```rust +impl pallet_file_bank::Config for Runtime { + // ... + type OssFindAuthor = Oss; + // ... +} +``` diff --git a/pallets/sminer/README.md b/pallets/sminer/README.md old mode 100644 new mode 100755 index 6a9c0ded..f83583aa --- a/pallets/sminer/README.md +++ b/pallets/sminer/README.md @@ -1,28 +1,95 @@ -# Sminer Module +# Cess Treasury Module -Contain operations related storage miners. +One of the core pallets of CESS, used to manage storage nodes. -### Terminology +## Overview -* **Collateral:** The Staking amount when registering storage miner. -* **Earnings:** Store the storage miner's earnings during mining. -* **Locked:** Store the locked amount of the storage miner during mining. +In addition to registering and changing the basic information of storage nodes, this module also includes the work of rewarding and punishing storage nodes. If you want to know more details about storage nodes, you can view the [wiki](https://docs.cess.cloud/core/storage-miner). + +## Terminology + +* **beneficiary:** The revenue account of the storage node is used to receive rewards from the storage node. +* **staking_val & collaterals:** The pledge amount of the storage node affects the storage space that the storage node can currently provide. +* **pois_key:** The secret key generated by the tee worker for calculating free space. +* **bloom filter:** Bloom filter for service files. The hash of the service file is encoded and recorded in the Bloom filter to compare whether the file is missing. + +## Extrinsic + +* `regnstk()` - Storage node registration function. This function will initialize the meta information of the storage node after staking it, including the reward table. +* `register_pois_key()` - This function is used to register the pois_key of the storage node. After completing this step, the storage node can start mining. +* `increase_collateral()` - Storage nodes add pledge function. +* `update_beneficiary()` - This function is used to update the revenue address of the storage node. +* `update_peer_id()` - This function is used to update the peer_id field of the storage node. +* `receive_reward()` - Used for storage nodes to receive rewards, and the rewards will be transferred to the income account. +* `miner_exit_prep()` - Storage node pre-exit function. After calling this method, the storage node will enter the lock period and start a scheduler task. +* `miner_exit()` - Triggered by the chain itself. It is the execution object of the scheduler task created in miner_exit_pre(). Some information processing required for storage node exit will be performed. +* `miner_withdraw()` - Storage node redemption and pledge function. It can be called by the storage node after completing the exit process to redeem the current pledge. +* `faucet_top_up()` - Testnet exclusive method. Recharge the faucet account. +* `faucet()` - Faucet water function. An account can only be called once a day to receive 10,000 TCESS. +* `update_expender()` - Can only be called by root privileges and is used to change the graph specification of idle files generated by storage nodes. ## Interface -### Dispatchable Functions - -* `regnstk` - Staking and register for storage miner. -* `increase_collateral` - Additional pledge method for miners. -* `update_beneficiary` -Miner replacement income account. -* `update_ip` - Miner changes IP endpoint address. -* `timing_storage_space` - A scheduled task for computing power trend data of the entire network. -* `timing_storage_space_thirty_days` - Generate power trend data for the first 30 days. -* `timed_increase_rewards` - Add reward orders. -* `timing_task_increase_power_rewards` - Added timed tasks for reward orders. -* `timed_user_receive_award1` - Users receive rewards for scheduled tasks. -* `faucet_top_up` - Obtain transaction token from faucet. -* `faucet` - Users receive money through the faucet. -* `increase_collateral` - Increase additional deposit for miners. -* `exit_miner` - Storage Miner exit system. -* `withdraw` - Miners redeem deposit. +### MinerControl + +Used to update or check the information status of storage nodes, and also includes related functions for rewards and penalties for storage nodes. + +#### Function + +* `add_miner_idle_space()` - Increase the free space of storage nodes. +* `delete_idle_update_accu()` - Reduce idle files on storage nodes and update filters. +* `delete_idle_update_space()` - Reduce idle space on storage nodes. +* `add_miner_service_space()` - Increase the service space of storage nodes. +* `sub_miner_service_space()` - Reduce the service space of storage nodes. +* `get_power()` - Get storage node computing power. +* `miner_is_exist()` - Determine whether the storage node exists. +* `get_miner_state()` - Get storage node status. +* `get_all_miner()` - Get a list of all storage node accounts. +* `insert_service_bloom()` - Service file bloom filter inserts new files. +* `delete_service_bloom()` - Remove specified files from service file bloom filter. +* `lock_space()` - Lock the idle space of the storage node. +* `unlock_space()` - Release the locked space of the storage node. +* `unlock_space_to_service()` - Release the locked space of the storage node and increase the corresponding service space. +* `get_miner_idle_space()` - Get the idle space of the storage node. +* `get_miner_count()` - Get the number of storage nodes in the current network. +* `calculate_miner_reward()` - Calculate storage node rewards and update its reward table. +* `clear_punish()` - Clear punish the storage node. +* `idle_punish()` - Implement idle punishment on storage nodes. +* `service_punish()` - Implement service punishment on storage nodes. +* `force_miner_exit()` - Force the storage node to be kicked out of the network. +* `update_restoral_target()` - Update recovery target state. +* `restoral_target_is_exist()` - Whether the recovery target exists. +* `is_positive()` - Whether it is an positive storage node. +* `is_lock()` - Whether it is an lock storage node. +* `update_miner_state()` - Update storage node status. +* `get_expenders()` - Get the current expander specification. +* `get_miner_snapshot()` - Obtain the snapshot information of the storage node for random challenges. + +#### Usage +in pallet::Config +```rust +pub trait Config: + frame_system::Config + sp_std::fmt::Debug + { + //... + type MinerControl: MinerControl; + //... + } +``` +in runtime.rs +```rust +impl pallet_audit::Config for Runtime { + //... + type MinerControl = Sminer; + //... +} +``` + +## Implementation Details + +### Reward Calculation + +The reward of a storage node will be determined by the ratio of its service space and idle space to the total computing power of the entire network. +The reward will be calculated based on the snapshot of the storage node recorded when the random challenge started, rather than the current state of the storage node. +Read the [wiki documentation](https://docs.cess.cloud/core/storage-miner/reward) to learn about the reward calculation formula and more reward details for storage nodes. + diff --git a/pallets/sminer/src/constants.rs b/pallets/sminer/src/constants.rs index 83038996..52c7ab8f 100644 --- a/pallets/sminer/src/constants.rs +++ b/pallets/sminer/src/constants.rs @@ -28,4 +28,4 @@ pub(super) const IDLE_PUNI_MUTI: Perbill = Perbill::from_percent(10); pub(super) const SERVICE_PUNI_MUTI: Perbill = Perbill::from_percent(25); -pub(super) const BASE_LIMIT: u128 = 4_000_000_000_000_000; \ No newline at end of file +pub(super) const BASE_UNIT: u128 = 4_000_000_000_000_000; \ No newline at end of file diff --git a/pallets/sminer/src/functions.rs b/pallets/sminer/src/functions.rs index fee466b8..fe67ca44 100644 --- a/pallets/sminer/src/functions.rs +++ b/pallets/sminer/src/functions.rs @@ -42,7 +42,7 @@ impl Pallet { let miner_info = miner_info_opt.as_mut().ok_or(Error::::NotMiner)?; if miner_info.collaterals > punish_amount { - T::Currency::unreserve(miner, punish_amount); + T::Currency::unreserve(&miner_info.staking_account, punish_amount); T::CessTreasuryHandle::send_to_pid(miner.clone(), punish_amount)?; miner_info.collaterals = miner_info.collaterals.checked_sub(&punish_amount).ok_or(Error::::Overflow)?; } else { @@ -53,7 +53,8 @@ impl Pallet { } let power = Self::calculate_power(miner_info.idle_space, miner_info.service_space); - let limit = Self::check_collateral_limit(power)?; + let limit: BalanceOf = Self::calculate_limit_by_space(power)? + .try_into().map_err(|_| Error::::Overflow)?; if miner_info.collaterals < limit { miner_info.state = Self::str_to_bound(STATE_FROZEN)?; @@ -65,14 +66,6 @@ impl Pallet { Ok(()) } - pub(super) fn check_collateral_limit(power: u128) -> Result, Error> { - let limit = 1 + power.checked_div(T_BYTE).ok_or(Error::::Overflow)?; - let limit = BASE_LIMIT.checked_mul(limit).ok_or(Error::::Overflow)?; - let limit: BalanceOf = limit.try_into().map_err(|_| Error::::Overflow)?; - - Ok(limit) - } - pub(super) fn check_state(acc: &AccountOf) -> Result, Error> { Ok(>::try_get(acc).map_err(|_e| Error::::NotMiner)?.state.to_vec()) } @@ -126,15 +119,26 @@ impl Pallet { } // Note: that it is necessary to determine whether the state meets the exit conditions before use. - pub(super) fn withdraw(acc: &AccountOf) -> DispatchResult { - let miner_info = >::try_get(acc).map_err(|_| Error::::NotMiner)?; - T::Currency::unreserve(acc, miner_info.collaterals); + pub(super) fn withdraw(miner: AccountOf) -> DispatchResult { + let miner_info = >::try_get(&miner).map_err(|_| Error::::NotMiner)?; + T::Currency::unreserve(&miner_info.staking_account, miner_info.collaterals); let space_proof_info = miner_info.space_proof_info.ok_or(Error::::NotpositiveState)?; let encoding = space_proof_info.pois_key.encode(); let hashing = sp_io::hashing::sha2_256(&encoding); MinerPublicKey::::remove(hashing); - >::remove(acc); + >::remove(miner); Ok(()) } + + pub(super) fn calculate_limit_by_space(space: u128) -> Result { + let mut tib_count = space.checked_div(T_BYTE).ok_or(Error::::Overflow)?; + if space % T_BYTE != 0 { + tib_count = tib_count.checked_add(1).ok_or(Error::::Overflow)?; + } + + let collaterals_limit = tib_count.checked_mul(BASE_UNIT).ok_or(Error::::Overflow)?; + + Ok(collaterals_limit) + } } \ No newline at end of file diff --git a/pallets/sminer/src/helper.rs b/pallets/sminer/src/helper.rs index c5444139..b064ab9a 100644 --- a/pallets/sminer/src/helper.rs +++ b/pallets/sminer/src/helper.rs @@ -3,7 +3,8 @@ use super::*; impl Pallet { pub(super) fn add_miner_idle_space( acc: &AccountOf, - accumulator: Accumulator, + accumulator: Accumulator, + check_front: u64, rear: u64, tee_sig: TeeRsaSignature, ) -> Result { @@ -15,6 +16,7 @@ impl Pallet { let mut space_proof_info = miner_info.space_proof_info.clone().ok_or(Error::::NotpositiveState)?; + ensure!(check_front == space_proof_info.front, Error::::CountError); ensure!(space_proof_info.rear < rear, Error::::CountError); let count = rear.checked_sub(space_proof_info.rear).ok_or(Error::::Overflow)?; @@ -26,6 +28,12 @@ impl Pallet { miner_info.idle_space = miner_info.idle_space.checked_add(idle_space).ok_or(Error::::Overflow)?; + + let currency_cert_space = miner_info.idle_space + .checked_add(miner_info.service_space).ok_or(Error::::Overflow)? + .checked_add(miner_info.lock_space).ok_or(Error::::Overflow)?; + + ensure!(currency_cert_space <= miner_info.declaration_space, Error::::ExceedingDeclarationSpace); miner_info.tee_signature = tee_sig; @@ -38,7 +46,8 @@ impl Pallet { pub(super) fn delete_idle_update_accu( acc: &AccountOf, accumulator: Accumulator, - front: u64, + front: u64, + check_rear: u64, tee_sig: TeeRsaSignature, ) -> Result { MinerItems::::try_mutate(acc, |miner_info_opt| -> Result { @@ -46,6 +55,7 @@ impl Pallet { let mut space_proof_info = miner_info.space_proof_info.clone().ok_or(Error::::NotpositiveState)?; + ensure!(check_rear == space_proof_info.rear, Error::::CountError); ensure!(space_proof_info.front < front, Error::::CountError); let count = front - space_proof_info.front; @@ -204,7 +214,8 @@ impl Pallet { pub(super) fn clear_punish(miner: &AccountOf, level: u8, idle_space: u128, service_space: u128) -> DispatchResult { let power = Self::calculate_power(idle_space, service_space); - let limit = Self::check_collateral_limit(power)?; + let limit: BalanceOf = Self::calculate_limit_by_space(power)? + .try_into().map_err(|_| Error::::Overflow)?; // FOR TESTING let punish_amount = match level { 1 => Perbill::from_percent(30).mul_floor(limit), @@ -220,7 +231,8 @@ impl Pallet { pub(super) fn idle_punish(miner: &AccountOf, idle_space: u128, service_space: u128) -> DispatchResult { let power = Self::calculate_power(idle_space, service_space); - let limit = Self::check_collateral_limit(power)?; + let limit: BalanceOf = Self::calculate_limit_by_space(power)? + .try_into().map_err(|_| Error::::Overflow)?; let punish_amount = IDLE_PUNI_MUTI.mul_floor(limit); @@ -231,7 +243,8 @@ impl Pallet { pub(super) fn service_punish(miner: &AccountOf, idle_space: u128, service_space: u128) -> DispatchResult { let power = Self::calculate_power(idle_space, service_space); - let limit = Self::check_collateral_limit(power)?; + let limit: BalanceOf = Self::calculate_limit_by_space(power)? + .try_into().map_err(|_| Error::::Overflow)?; let punish_amount = SERVICE_PUNI_MUTI.mul_floor(limit); @@ -255,6 +268,7 @@ impl Pallet { >::try_mutate(acc, |miner_opt| -> DispatchResult { let miner = miner_opt.as_mut().ok_or(Error::::Unexpected)?; T::StorageHandle::sub_total_idle_space(miner.idle_space + miner.lock_space)?; + T::Currency::unreserve(&miner.staking_account, miner.collaterals); Self::create_restoral_target(acc, miner.service_space)?; miner.state = Self::str_to_bound(STATE_OFFLINE)?; let space_proof_info = miner.space_proof_info.clone().ok_or(Error::::NotpositiveState)?; diff --git a/pallets/sminer/src/lib.rs b/pallets/sminer/src/lib.rs index 8656b6ad..fb1ccb40 100644 --- a/pallets/sminer/src/lib.rs +++ b/pallets/sminer/src/lib.rs @@ -99,6 +99,9 @@ pub mod pallet { #[pallet::constant] type OneDayBlock: Get>; + + #[pallet::constant] + type StakingLockBlock: Get>; /// The WeightInfo. type WeightInfo: WeightInfo; @@ -123,7 +126,6 @@ pub mod pallet { /// A new account was set. Registered { acc: AccountOf, - staking_val: BalanceOf, }, RegisterPoisKey { miner: AccountOf, @@ -171,6 +173,10 @@ pub mod pallet { Withdraw { acc: AccountOf }, + IncreaseDeclarationSpace { + miner: AccountOf, + space: u128, + }, } /// Error for the sminer pallet. @@ -217,6 +223,14 @@ pub mod pallet { BloomElemPushError, CollateralNotUp, + + NotStakingAcc, + + BugInvalid, + + InsufficientStakingPeriod, + + ExceedingDeclarationSpace, } /// The hashmap for info of storage miners. @@ -266,7 +280,12 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn restoral_target)] pub(super) type RestoralTarget = - StorageMap< _, Blake2_128Concat, AccountOf, RestoralTargetInfo, BlockNumberFor>>; + StorageMap<_, Blake2_128Concat, AccountOf, RestoralTargetInfo, BlockNumberFor>>; + + #[pallet::storage] + #[pallet::getter(fn staking_start_block)] + pub(super) type StakingStartBlock = + StorageMap<_, Blake2_128Concat, AccountOf, BlockNumberFor>; #[pallet::pallet] pub struct Pallet(_); @@ -317,20 +336,29 @@ pub mod pallet { beneficiary: AccountOf, peer_id: PeerId, staking_val: BalanceOf, + tib_count: u32, ) -> DispatchResult { let sender = ensure_signed(origin)?; ensure!(!(>::contains_key(&sender)), Error::::AlreadyRegistered); - ensure!(staking_val >= BASE_LIMIT.try_into().map_err(|_| Error::::Overflow)?, Error::::CollateralNotUp); + let declaration_space = T_BYTE.checked_mul(tib_count as u128).ok_or(Error::::Overflow)?; + let base_limit: BalanceOf = Self::calculate_limit_by_space(declaration_space)? + .try_into().map_err(|_| Error::::Overflow)?; + ensure!(staking_val >= base_limit.try_into().map_err(|_| Error::::Overflow)?, Error::::CollateralNotUp); T::Currency::reserve(&sender, staking_val)?; + let now = >::block_number(); + >::insert(&sender, now); + >::insert( &sender, MinerInfo:: { beneficiary: beneficiary.clone(), + staking_account: sender.clone(), peer_id: peer_id, collaterals: staking_val, debt: BalanceOf::::zero(), state: Self::str_to_bound(STATE_NOT_READY)?, + declaration_space: declaration_space, idle_space: u128::MIN, service_space: u128::MIN, lock_space: u128::MIN, @@ -352,7 +380,6 @@ pub mod pallet { Self::deposit_event(Event::::Registered { acc: sender, - staking_val: staking_val, }); Ok(()) @@ -390,7 +417,13 @@ pub mod pallet { ensure!(STATE_NOT_READY.as_bytes().to_vec() == miner_info.state.to_vec(), Error::::StateError); miner_info.space_proof_info = Some(space_proof_info); - miner_info.state = Self::str_to_bound(STATE_POSITIVE)?; + let base_limit: BalanceOf = Self::calculate_limit_by_space(miner_info.declaration_space)? + .try_into().map_err(|_| Error::::Overflow)?; + if miner_info.collaterals >= base_limit { + miner_info.state = Self::str_to_bound(STATE_POSITIVE)?; + } else { + miner_info.state = Self::str_to_bound(STATE_FROZEN)?; + } miner_info.tee_signature = tee_sig; Ok(()) @@ -410,6 +443,88 @@ pub mod pallet { Ok(()) } + #[pallet::call_index(17)] + #[transactional] + #[pallet::weight(::WeightInfo::regnstk())] + pub fn regnstk_assign_staking( + origin: OriginFor, + beneficiary: AccountOf, + peer_id: PeerId, + staking_account: AccountOf, + tib_count: u32, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + ensure!(!(>::contains_key(&sender)), Error::::AlreadyRegistered); + let declaration_space = T_BYTE.checked_mul(tib_count as u128).ok_or(Error::::Overflow)?; + + >::insert( + &sender, + MinerInfo:: { + beneficiary: beneficiary.clone(), + staking_account: staking_account.clone(), + peer_id: peer_id, + collaterals: BalanceOf::::zero(), + debt: BalanceOf::::zero(), + state: Self::str_to_bound(STATE_NOT_READY)?, + declaration_space: declaration_space, + idle_space: u128::MIN, + service_space: u128::MIN, + lock_space: u128::MIN, + space_proof_info: Option::None, + service_bloom_filter: Default::default(), + tee_signature: [0u8; 256], + }, + ); + + RewardMap::::insert( + &sender, + Reward::{ + total_reward: 0u32.saturated_into(), + reward_issued: 0u32.saturated_into(), + currently_available_reward: 0u32.saturated_into(), + order_list: Default::default() + }, + ); + + Self::deposit_event(Event::::Registered { + acc: sender, + }); + + Ok(()) + } + + #[pallet::call_index(18)] + #[transactional] + #[pallet::weight(::WeightInfo::increase_collateral())] + pub fn increase_declaration_space(origin: OriginFor, tib_count: u32) -> DispatchResult { + let sender = ensure_signed(origin)?; + + ensure!(MinerItems::::contains_key(&sender), Error::::NotMiner); + let increase_space = T_BYTE.checked_mul(tib_count as u128).ok_or(Error::::Overflow)?; + + >::try_mutate(&sender, |miner_info_opt| -> DispatchResult { + let miner_info = miner_info_opt.as_mut().ok_or(Error::::ConversionError)?; + + ensure!(miner_info.state.to_vec() == STATE_POSITIVE.as_bytes().to_vec(), Error::::StateError); + miner_info.declaration_space = miner_info.declaration_space + .checked_add(increase_space).ok_or(Error::::Overflow)?; + let base_limit: BalanceOf = Self::calculate_limit_by_space(miner_info.declaration_space)? + .try_into().map_err(|_| Error::::Overflow)?; + if base_limit > miner_info.collaterals { + miner_info.state = Self::str_to_bound(STATE_FROZEN)?; + } + + Ok(()) + })?; + + Self::deposit_event(Event::::IncreaseDeclarationSpace { + miner: sender, + space: increase_space, + }); + + Ok(()) + } + /// Increase Collateral and Update Miner's State /// /// This function allows a registered Miner to increase their staked collateral. @@ -423,18 +538,20 @@ pub mod pallet { #[pallet::weight(::WeightInfo::increase_collateral())] pub fn increase_collateral( origin: OriginFor, + miner: AccountOf, #[pallet::compact] collaterals: BalanceOf, ) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(MinerItems::::contains_key(&sender), Error::::NotMiner); + ensure!(MinerItems::::contains_key(&miner), Error::::NotMiner); let mut balance: BalanceOf = 0u32.saturated_into(); - >::try_mutate(&sender, |miner_info_opt| -> DispatchResult { + >::try_mutate(&miner, |miner_info_opt| -> DispatchResult { let miner_info = miner_info_opt.as_mut().ok_or(Error::::ConversionError)?; ensure!(miner_info.state.to_vec() != STATE_OFFLINE.as_bytes().to_vec(), Error::::StateError); ensure!(miner_info.state.to_vec() != STATE_LOCK.as_bytes().to_vec(), Error::::StateError); ensure!(miner_info.state.to_vec() != STATE_EXIT.as_bytes().to_vec(), Error::::StateError); + ensure!(miner_info.staking_account == sender, Error::::NotStakingAcc); let mut remaining = collaterals; if miner_info.debt > BalanceOf::::zero() { @@ -456,12 +573,16 @@ pub mod pallet { if miner_info.state == STATE_FROZEN.as_bytes().to_vec() { let power = Self::calculate_power(miner_info.idle_space, miner_info.service_space); - let limit = Self::check_collateral_limit(power)?; + let limit = Self::calculate_limit_by_space(power)? + .try_into().map_err(|_| Error::::Overflow)?; if miner_info.collaterals >= limit { miner_info.state = Self::str_to_bound(STATE_POSITIVE)?; } } + let now = >::block_number(); + >::insert(&sender, now); + T::Currency::reserve(&sender, remaining)?; Ok(()) @@ -583,23 +704,31 @@ pub mod pallet { #[pallet::weight(::WeightInfo::miner_exit_prep())] pub fn miner_exit_prep( origin: OriginFor, + miner: AccountOf, ) -> DispatchResult { let sender = ensure_signed(origin)?; + let now = >::block_number(); if let Ok(lock_time) = >::try_get(&sender) { - let now = >::block_number(); ensure!(now > lock_time, Error::::StateError); } + let staking_start_block = >::try_get(&miner).map_err(|_| Error::::BugInvalid)?; + let staking_lock_block = T::StakingLockBlock::get(); + ensure!(now > staking_start_block + staking_lock_block, Error::::InsufficientStakingPeriod); - >::try_mutate(&sender, |miner_opt| -> DispatchResult { - let miner = miner_opt.as_mut().ok_or(Error::::NotExisted)?; - ensure!(miner.state == STATE_POSITIVE.as_bytes().to_vec(), Error::::StateError); - ensure!(miner.lock_space == 0, Error::::StateError); - if miner.lock_space != 0 { + >::try_mutate(&sender, |miner_info_opt| -> DispatchResult { + + let miner_info = miner_info_opt.as_mut().ok_or(Error::::NotExisted)?; + if (&sender != &miner) && (&sender != &miner_info.staking_account) { + Err(Error::::NotStakingAcc)?; + } + ensure!(miner_info.state == STATE_POSITIVE.as_bytes().to_vec(), Error::::StateError); + ensure!(miner_info.lock_space == 0, Error::::StateError); + if miner_info.lock_space != 0 { Err(Error::::StateError)?; } - miner.state = Self::str_to_bound(STATE_LOCK)?; + miner_info.state = Self::str_to_bound(STATE_LOCK)?; Ok(()) })?; @@ -608,19 +737,19 @@ pub mod pallet { // TODO! Develop a lock-in period based on the maximum duration of the current challenge let lock_time = T::OneDayBlock::get().checked_add(&now).ok_or(Error::::Overflow)?; - >::insert(&sender, lock_time); + >::insert(&miner, lock_time); - let task_id: Vec = sender.encode(); + let task_id: Vec = miner.encode(); T::FScheduler::schedule_named( task_id, DispatchTime::At(lock_time), Option::None, schedule::HARD_DEADLINE, frame_system::RawOrigin::Root.into(), - Call::miner_exit{miner: sender.clone()}.into(), + Call::miner_exit{miner: miner.clone()}.into(), ).map_err(|_| Error::::Unexpected)?; - Self::deposit_event(Event::::MinerExitPrep{ miner: sender }); + Self::deposit_event(Event::::MinerExitPrep{ miner: miner }); Ok(()) } @@ -677,7 +806,7 @@ pub mod pallet { Err(Error::::StateError)?; } - Self::withdraw(&sender)?; + Self::withdraw(sender.clone())?; Self::deposit_event(Event::::Withdraw { acc: sender, @@ -685,6 +814,7 @@ pub mod pallet { Ok(()) } + /// Punish offline miners. /// /// The dispatch origin of this call must be _root_. @@ -814,9 +944,9 @@ pub mod pallet { } pub trait MinerControl { - fn add_miner_idle_space(acc: &AccountId, accumulator: Accumulator, rear: u64, tee_sig: TeeRsaSignature) -> Result; + fn add_miner_idle_space(acc: &AccountId, accumulator: Accumulator, check_front: u64, rear: u64, tee_sig: TeeRsaSignature) -> Result; // fn sub_miner_idle_space(acc: &AccountId, accumulator: Accumulator, rear: u64) -> DispatchResult; - fn delete_idle_update_accu(acc: &AccountId, accumulator: Accumulator, front: u64, tee_sig: TeeRsaSignature) -> Result; + fn delete_idle_update_accu(acc: &AccountId, accumulator: Accumulator, front: u64, check_rear: u64, tee_sig: TeeRsaSignature) -> Result; fn delete_idle_update_space(acc: &AccountId, idle_space: u128) -> DispatchResult; fn add_miner_service_space(acc: &AccountId, power: u128) -> DispatchResult; fn sub_miner_service_space(acc: &AccountId, power: u128) -> DispatchResult; @@ -862,12 +992,14 @@ impl MinerControl<::AccountId, BlockNumber fn add_miner_idle_space( acc: &::AccountId, accumulator: Accumulator, + check_front: u64, rear: u64, tee_sig: TeeRsaSignature ) -> Result { let idle_space = Pallet::::add_miner_idle_space( acc, accumulator, + check_front, rear, tee_sig )?; @@ -877,13 +1009,15 @@ impl MinerControl<::AccountId, BlockNumber fn delete_idle_update_accu( acc: &AccountOf, accumulator: Accumulator, - front: u64, + front: u64, + check_rear: u64, tee_sig: TeeRsaSignature ) -> Result { let count = Self::delete_idle_update_accu( acc, accumulator, front, + check_rear, tee_sig )?; diff --git a/pallets/sminer/src/types.rs b/pallets/sminer/src/types.rs index 37b5c073..810ea1a5 100644 --- a/pallets/sminer/src/types.rs +++ b/pallets/sminer/src/types.rs @@ -8,11 +8,13 @@ use frame_support::pallet_prelude::MaxEncodedLen; pub struct MinerInfo { //Income account pub(super) beneficiary: AccountOf, + pub(super) staking_account: AccountOf, pub(super) peer_id: PeerId, pub(super) collaterals: BalanceOf, pub(super) debt: BalanceOf, //nomal, exit, frozen, e_frozen pub(super) state: BoundedVec, + pub(super) declaration_space: u128, pub(super) idle_space: u128, pub(super) service_space: u128, pub(super) lock_space: u128, diff --git a/pallets/tee-worker/README.md b/pallets/tee-worker/README.md old mode 100644 new mode 100755 diff --git a/standalone/chain/runtime/src/lib.rs b/standalone/chain/runtime/src/lib.rs index 2fbf7969..18737d94 100644 --- a/standalone/chain/runtime/src/lib.rs +++ b/standalone/chain/runtime/src/lib.rs @@ -1035,6 +1035,8 @@ impl pallet_proxy::Config for Runtime { */ parameter_types! { pub const FaucetId: PalletId = PalletId(*b"facuetid"); + #[derive(Clone, Eq, PartialEq)] + pub const StakingLockBlock: BlockNumber = DAYS * 180; } impl pallet_sminer::Config for Runtime { @@ -1045,6 +1047,7 @@ impl pallet_sminer::Config for Runtime { type WeightInfo = pallet_sminer::weights::SubstrateWeight; type ItemLimit = ConstU32<200000>; type OneDayBlock = OneDay; + type StakingLockBlock = StakingLockBlock; type TeeWorkerHandler = TeeWorker; type FScheduler = Scheduler; type AScheduler = Scheduler;