From a9ada37a98c447884d2099f2ec568451587e0b5c Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 5 Jan 2024 15:16:15 +0200 Subject: [PATCH 1/3] Support enabling rewards at solution range (either in chain spec or with an extrinsic) --- crates/pallet-subspace/src/benchmarking.rs | 9 +- crates/pallet-subspace/src/lib.rs | 91 +++++++++++++++++---- crates/pallet-subspace/src/mock.rs | 6 +- crates/pallet-subspace/src/tests.rs | 66 ++++++++++++++- crates/subspace-node/src/chain_spec.rs | 20 ++--- crates/subspace-runtime/src/lib.rs | 2 +- test/subspace-test-client/src/chain_spec.rs | 8 +- test/subspace-test-runtime/src/lib.rs | 2 +- 8 files changed, 165 insertions(+), 39 deletions(-) diff --git a/crates/pallet-subspace/src/benchmarking.rs b/crates/pallet-subspace/src/benchmarking.rs index 72c105b0e1..106cca56a2 100644 --- a/crates/pallet-subspace/src/benchmarking.rs +++ b/crates/pallet-subspace/src/benchmarking.rs @@ -5,7 +5,7 @@ use frame_benchmarking::v2::*; #[benchmarks] mod benchmarks { use crate::{ - AllowAuthoringByAnyone, Call, Config, CurrentSlot, EnableRewards, + AllowAuthoringByAnyone, Call, Config, CurrentSlot, EnableRewards, EnableRewardsAt, NextSolutionRangeOverride, Pallet, SegmentCommitment, ShouldAdjustSolutionRange, SolutionRanges, }; @@ -123,11 +123,14 @@ mod benchmarks { } #[benchmark] - fn enable_rewards() { + fn enable_rewards_at() { EnableRewards::::take(); #[extrinsic_call] - _(RawOrigin::Root, Some(100u32.into())); + _( + RawOrigin::Root, + EnableRewardsAt::Height(Some(100u32.into())), + ); assert_eq!(EnableRewards::::get(), Some(100u32.into())); } diff --git a/crates/pallet-subspace/src/lib.rs b/crates/pallet-subspace/src/lib.rs index 09341dc893..decc985df3 100644 --- a/crates/pallet-subspace/src/lib.rs +++ b/crates/pallet-subspace/src/lib.rs @@ -263,10 +263,25 @@ pub mod pallet { pub(super) entropy: Blake3Hash, } + /// When to enable block/vote rewards + #[derive(Debug, Copy, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub enum EnableRewardsAt { + /// At specified height or next block if `None` + Height(Option), + /// When solution range is below specified threshold + SolutionRange(u64), + /// Manually with an explicit extrinsic + Manually, + } + #[pallet::genesis_config] - pub struct GenesisConfig { - /// Whether rewards should be enabled. - pub enable_rewards: bool, + pub struct GenesisConfig + where + T: Config, + { + /// When rewards should be enabled. + pub enable_rewards_at: EnableRewardsAt>, /// Whether storage access should be enabled. pub enable_storage_access: bool, /// Who can author blocks at genesis. @@ -277,7 +292,10 @@ pub mod pallet { pub phantom: PhantomData, } - impl Default for GenesisConfig { + impl Default for GenesisConfig + where + T: Config, + { #[inline] #[track_caller] fn default() -> Self { @@ -288,10 +306,23 @@ pub mod pallet { } #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { + impl BuildGenesisConfig for GenesisConfig + where + T: Config, + { fn build(&self) { - if self.enable_rewards { - EnableRewards::::put::>(sp_runtime::traits::One::one()); + match self.enable_rewards_at { + EnableRewardsAt::Height(maybe_block_number) => { + EnableRewards::::put( + maybe_block_number.unwrap_or_else(sp_runtime::traits::One::one), + ); + } + EnableRewardsAt::SolutionRange(solution_range) => { + EnableRewardsBelowSolutionRange::::put(solution_range); + } + EnableRewardsAt::Manually => { + // Nothing to do in this case + } } IsStorageAccessEnabled::::put(self.enable_storage_access); match &self.allow_authoring_by { @@ -409,6 +440,10 @@ pub mod pallet { #[pallet::storage] pub(super) type EnableRewards = StorageValue<_, BlockNumberFor>; + /// Enable rewards when solution range is blow this threshold. + #[pallet::storage] + pub(super) type EnableRewardsBelowSolutionRange = StorageValue<_, u64>; + /// Temporary value (cleared at block finalization) with block author information. #[pallet::storage] pub(super) type CurrentBlockAuthorInfo = StorageValue< @@ -558,13 +593,13 @@ pub mod pallet { /// Enable rewards for blocks and votes at specified block height. #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::enable_rewards())] - pub fn enable_rewards( + pub fn enable_rewards_at( origin: OriginFor, - height: Option>, + enable_rewards_at: EnableRewardsAt>, ) -> DispatchResult { ensure_root(origin)?; - Self::do_enable_rewards(height) + Self::do_enable_rewards_at(enable_rewards_at) } /// Enable storage access for all users. @@ -732,6 +767,16 @@ impl Pallet { solution_ranges .voting_next .replace(next_voting_solution_range); + + if let Some(solution_range_for_rewards) = EnableRewardsBelowSolutionRange::::get() { + if next_solution_range <= solution_range_for_rewards { + EnableRewardsBelowSolutionRange::::take(); + + let next_block_number = + frame_system::Pallet::::current_block_number() + One::one(); + EnableRewards::::put(next_block_number); + } + } }); EraStartSlot::::put(current_slot); @@ -1059,14 +1104,32 @@ impl Pallet { } } - fn do_enable_rewards(height: Option>) -> DispatchResult { + fn do_enable_rewards_at( + enable_rewards_at: EnableRewardsAt>, + ) -> DispatchResult { if EnableRewards::::get().is_some() { return Err(Error::::RewardsAlreadyEnabled.into()); } - // Enable rewards at a particular block height (default to the next block after this) - let next_block_number = frame_system::Pallet::::current_block_number() + One::one(); - EnableRewards::::put(height.unwrap_or(next_block_number).max(next_block_number)); + match enable_rewards_at { + EnableRewardsAt::Height(maybe_block_number) => { + // Enable rewards at a particular block height (default to the next block after + // this) + let next_block_number = + frame_system::Pallet::::current_block_number() + One::one(); + EnableRewards::::put( + maybe_block_number + .unwrap_or(next_block_number) + .max(next_block_number), + ); + } + EnableRewardsAt::SolutionRange(solution_range) => { + EnableRewardsBelowSolutionRange::::put(solution_range); + } + EnableRewardsAt::Manually => { + // Nothing to do in this case + } + } Ok(()) } diff --git a/crates/pallet-subspace/src/mock.rs b/crates/pallet-subspace/src/mock.rs index bdbf12795b..a443d25c39 100644 --- a/crates/pallet-subspace/src/mock.rs +++ b/crates/pallet-subspace/src/mock.rs @@ -18,8 +18,8 @@ use crate::equivocation::EquivocationHandler; use crate::{ - self as pallet_subspace, AllowAuthoringBy, Config, CurrentSlot, FarmerPublicKey, - NormalEraChange, + self as pallet_subspace, AllowAuthoringBy, Config, CurrentSlot, EnableRewardsAt, + FarmerPublicKey, NormalEraChange, }; use frame_support::parameter_types; use frame_support::traits::{ConstU128, ConstU16, ConstU32, ConstU64, OnInitialize}; @@ -297,7 +297,7 @@ pub fn new_test_ext(pot_extension: PotExtension) -> TestExternalities { .unwrap(); pallet_subspace::GenesisConfig:: { - enable_rewards: true, + enable_rewards_at: EnableRewardsAt::Height(Some(1)), enable_storage_access: true, allow_authoring_by: AllowAuthoringBy::Anyone, pot_slot_iterations: NonZeroU32::new(100_000).unwrap(), diff --git a/crates/pallet-subspace/src/tests.rs b/crates/pallet-subspace/src/tests.rs index 78c77d3f77..71ed8d13e9 100644 --- a/crates/pallet-subspace/src/tests.rs +++ b/crates/pallet-subspace/src/tests.rs @@ -24,8 +24,8 @@ use crate::mock::{ }; use crate::{ pallet, AllowAuthoringByAnyone, BlockList, Call, CheckVoteError, Config, - CurrentBlockAuthorInfo, CurrentBlockVoters, CurrentSlot, ParentBlockAuthorInfo, - ParentBlockVoters, SegmentCommitment, SubspaceEquivocationOffence, + CurrentBlockAuthorInfo, CurrentBlockVoters, CurrentSlot, EnableRewardsAt, + ParentBlockAuthorInfo, ParentBlockVoters, SegmentCommitment, SubspaceEquivocationOffence, }; use codec::Encode; use frame_support::dispatch::{GetDispatchInfo, Pays}; @@ -1600,7 +1600,12 @@ fn enabling_block_rewards_works() { assert_eq!(Subspace::find_voting_reward_addresses().len(), 0); // Enable since next block only rewards - crate::EnableRewards::::put(frame_system::Pallet::::current_block_number() + 1); + assert_ok!(Subspace::enable_rewards_at( + RuntimeOrigin::root(), + EnableRewardsAt::Height(Some( + frame_system::Pallet::::current_block_number() + 1, + )), + )); // No rewards yet assert_matches!(Subspace::find_block_reward_address(), None); assert_eq!(Subspace::find_voting_reward_addresses().len(), 0); @@ -1618,6 +1623,61 @@ fn enabling_block_rewards_works() { }); } +#[test] +fn enabling_block_rewards_at_solution_range_works() { + new_test_ext(allow_all_pot_extension()).execute_with(|| { + let keypair = Keypair::generate(); + + assert_eq!(::EraDuration::get(), 4); + assert_eq!( + ::InitialSolutionRange::get(), + INITIAL_SOLUTION_RANGE + ); + let initial_solution_ranges = SolutionRanges { + current: INITIAL_SOLUTION_RANGE, + next: None, + voting_current: INITIAL_SOLUTION_RANGE, + voting_next: None, + }; + assert_eq!(Subspace::solution_ranges(), initial_solution_ranges); + // enable solution range adjustment + assert_ok!(Subspace::enable_solution_range_adjustment( + RuntimeOrigin::root(), + None, + None + )); + // Disable rewards + crate::EnableRewards::::take(); + // Enable rewards below current solution range + assert_ok!(Subspace::enable_rewards_at( + RuntimeOrigin::root(), + EnableRewardsAt::SolutionRange(INITIAL_SOLUTION_RANGE - 1), + )); + + // Progress to almost era edge + progress_to_block(&keypair, 3, 1); + // No solution range update + assert_eq!(Subspace::solution_ranges(), initial_solution_ranges); + // Rewards are not enabled + assert_eq!(crate::EnableRewards::::get(), None); + + // Era edge + progress_to_block(&keypair, 4, 1); + // Next solution range should be updated, but current is still unchanged + let updated_solution_ranges = Subspace::solution_ranges(); + assert_eq!( + updated_solution_ranges.current, + initial_solution_ranges.current + ); + assert!(updated_solution_ranges.next.is_some()); + // Rewards will be enabled in the next block + assert_eq!( + crate::EnableRewards::::get(), + Some(frame_system::Pallet::::current_block_number() + 1) + ); + }) +} + #[test] fn allow_authoring_by_anyone_works() { new_test_ext(allow_all_pot_extension()).execute_with(|| { diff --git a/crates/subspace-node/src/chain_spec.rs b/crates/subspace-node/src/chain_spec.rs index 40f55c0634..483412672a 100644 --- a/crates/subspace-node/src/chain_spec.rs +++ b/crates/subspace-node/src/chain_spec.rs @@ -35,9 +35,9 @@ use std::marker::PhantomData; use std::num::NonZeroU32; use subspace_core_primitives::PotKey; use subspace_runtime::{ - AllowAuthoringBy, BalancesConfig, DomainsConfig, MaxDomainBlockSize, MaxDomainBlockWeight, - RuntimeConfigsConfig, RuntimeGenesisConfig, SubspaceConfig, SudoConfig, SystemConfig, - VestingConfig, MILLISECS_PER_BLOCK, WASM_BINARY, + AllowAuthoringBy, BalancesConfig, DomainsConfig, EnableRewardsAt, MaxDomainBlockSize, + MaxDomainBlockWeight, RuntimeConfigsConfig, RuntimeGenesisConfig, SubspaceConfig, SudoConfig, + SystemConfig, VestingConfig, MILLISECS_PER_BLOCK, WASM_BINARY, }; use subspace_runtime_primitives::{AccountId, Balance, BlockNumber, SSC}; @@ -97,7 +97,7 @@ const TOKEN_GRANTS: &[(&str, u128)] = &[ /// Additional subspace specific genesis parameters. struct GenesisParams { - enable_rewards: bool, + enable_rewards_at: EnableRewardsAt, enable_storage_access: bool, allow_authoring_by: AllowAuthoringBy, pot_slot_iterations: NonZeroU32, @@ -168,7 +168,7 @@ pub fn gemini_3g_compiled() -> Result, balances, vesting_schedules, GenesisParams { - enable_rewards: false, + enable_rewards_at: EnableRewardsAt::Manually, enable_storage_access: true, allow_authoring_by: AllowAuthoringBy::RootFarmer( FarmerPublicKey::unchecked_from(hex_literal::hex!( @@ -281,7 +281,7 @@ pub fn devnet_config_compiled() -> Result Result, String> ], vec![], GenesisParams { - enable_rewards: false, + enable_rewards_at: EnableRewardsAt::Manually, enable_storage_access: true, allow_authoring_by: AllowAuthoringBy::Anyone, pot_slot_iterations: NonZeroU32::new(100_000_000).expect("Not zero; qed"), @@ -414,7 +414,7 @@ pub fn local_config() -> Result, String ], vec![], GenesisParams { - enable_rewards: false, + enable_rewards_at: EnableRewardsAt::Manually, enable_storage_access: true, allow_authoring_by: AllowAuthoringBy::Anyone, pot_slot_iterations: NonZeroU32::new(100_000_000).expect("Not zero; qed"), @@ -462,7 +462,7 @@ fn subspace_genesis_config( genesis_domain_params: GenesisDomainParams, ) -> RuntimeGenesisConfig { let GenesisParams { - enable_rewards, + enable_rewards_at, enable_storage_access, allow_authoring_by, pot_slot_iterations, @@ -493,7 +493,7 @@ fn subspace_genesis_config( key: Some(sudo_account.clone()), }, subspace: SubspaceConfig { - enable_rewards, + enable_rewards_at, enable_storage_access, allow_authoring_by, pot_slot_iterations, diff --git a/crates/subspace-runtime/src/lib.rs b/crates/subspace-runtime/src/lib.rs index b8ebb1848c..3c4f15d758 100644 --- a/crates/subspace-runtime/src/lib.rs +++ b/crates/subspace-runtime/src/lib.rs @@ -44,7 +44,7 @@ use frame_support::weights::{ConstantMultiplier, IdentityFee, Weight}; use frame_support::{construct_runtime, parameter_types, PalletId}; use frame_system::limits::{BlockLength, BlockWeights}; use frame_system::EnsureNever; -pub use pallet_subspace::AllowAuthoringBy; +pub use pallet_subspace::{AllowAuthoringBy, EnableRewardsAt}; use pallet_transporter::EndpointHandler; use scale_info::TypeInfo; use sp_api::{impl_runtime_apis, BlockT}; diff --git a/test/subspace-test-client/src/chain_spec.rs b/test/subspace-test-client/src/chain_spec.rs index 846ebd9843..f456c96146 100644 --- a/test/subspace-test-client/src/chain_spec.rs +++ b/test/subspace-test-client/src/chain_spec.rs @@ -12,9 +12,9 @@ use std::marker::PhantomData; use std::num::NonZeroU32; use subspace_runtime_primitives::{AccountId, Balance, BlockNumber, Signature}; use subspace_test_runtime::{ - AllowAuthoringBy, BalancesConfig, DomainsConfig, MaxDomainBlockSize, MaxDomainBlockWeight, - RuntimeGenesisConfig, SubspaceConfig, SudoConfig, SystemConfig, VestingConfig, SSC, - WASM_BINARY, + AllowAuthoringBy, BalancesConfig, DomainsConfig, EnableRewardsAt, MaxDomainBlockSize, + MaxDomainBlockWeight, RuntimeGenesisConfig, SubspaceConfig, SudoConfig, SystemConfig, + VestingConfig, SSC, WASM_BINARY, }; /// The `ChainSpec` parameterized for subspace test runtime. @@ -102,7 +102,7 @@ fn create_genesis_config( key: Some(sudo_account.clone()), }, subspace: SubspaceConfig { - enable_rewards: false, + enable_rewards_at: EnableRewardsAt::Manually, enable_storage_access: false, allow_authoring_by: AllowAuthoringBy::Anyone, pot_slot_iterations: NonZeroU32::new(50_000_000).expect("Not zero; qed"), diff --git a/test/subspace-test-runtime/src/lib.rs b/test/subspace-test-runtime/src/lib.rs index 4a670c7dec..2ec3247127 100644 --- a/test/subspace-test-runtime/src/lib.rs +++ b/test/subspace-test-runtime/src/lib.rs @@ -40,7 +40,7 @@ use frame_support::{construct_runtime, parameter_types, PalletId}; use frame_system::limits::{BlockLength, BlockWeights}; use frame_system::EnsureNever; use pallet_balances::NegativeImbalance; -pub use pallet_subspace::AllowAuthoringBy; +pub use pallet_subspace::{AllowAuthoringBy, EnableRewardsAt}; use pallet_transporter::EndpointHandler; use scale_info::TypeInfo; use sp_api::{impl_runtime_apis, BlockT}; From d0ccb31abf27f752f508f8bd7fea89056e438f07 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 5 Jan 2024 15:16:33 +0200 Subject: [PATCH 2/3] Fix minor warnings in no-std environment --- crates/sp-domains/src/proof_provider_and_verifier.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/sp-domains/src/proof_provider_and_verifier.rs b/crates/sp-domains/src/proof_provider_and_verifier.rs index c48c9630c4..167bcd3c30 100644 --- a/crates/sp-domains/src/proof_provider_and_verifier.rs +++ b/crates/sp-domains/src/proof_provider_and_verifier.rs @@ -1,15 +1,19 @@ use frame_support::PalletError; use hash_db::Hasher; -use parity_scale_codec::{Codec, Compact, Decode, Encode}; +#[cfg(feature = "std")] +use parity_scale_codec::Codec; +use parity_scale_codec::{Compact, Decode, Encode}; use scale_info::TypeInfo; use sp_core::storage::StorageKey; #[cfg(feature = "std")] use sp_state_machine::prove_read; +#[cfg(feature = "std")] use sp_state_machine::TrieBackendBuilder; use sp_std::fmt::Debug; use sp_std::marker::PhantomData; use sp_std::vec::Vec; use sp_trie::{read_trie_value, LayoutV1, StorageProof}; +#[cfg(feature = "std")] use trie_db::{DBValue, TrieDBMutBuilder, TrieLayout, TrieMut}; /// Verification error. @@ -59,6 +63,7 @@ impl StorageProofVerifier { } } +#[cfg(feature = "std")] type MemoryDB = memory_db::MemoryDB< ::Hash, memory_db::HashKey<::Hash>, From fae3dfc3704ed02122e4bb71e20343598de3bdac Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 5 Jan 2024 20:53:42 +0200 Subject: [PATCH 3/3] Fix typo Co-authored-by: Jeremy Frank <37932802+jfrank-summit@users.noreply.github.com> --- crates/pallet-subspace/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pallet-subspace/src/lib.rs b/crates/pallet-subspace/src/lib.rs index decc985df3..26d35fc6f5 100644 --- a/crates/pallet-subspace/src/lib.rs +++ b/crates/pallet-subspace/src/lib.rs @@ -440,7 +440,7 @@ pub mod pallet { #[pallet::storage] pub(super) type EnableRewards = StorageValue<_, BlockNumberFor>; - /// Enable rewards when solution range is blow this threshold. + /// Enable rewards when solution range is below this threshold. #[pallet::storage] pub(super) type EnableRewardsBelowSolutionRange = StorageValue<_, u64>;