subspace_runtime_primitives/
lib.rs

1//! Runtime primitives for Subspace Network.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4
5pub mod utility;
6
7#[cfg(not(feature = "std"))]
8extern crate alloc;
9
10use crate::time::{BLOCKS_IN_AN_MINUTE, BLOCKS_IN_A_DAY};
11#[cfg(not(feature = "std"))]
12use alloc::vec::Vec;
13use core::marker::PhantomData;
14use frame_support::pallet_prelude::Weight;
15use frame_support::traits::tokens;
16use frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND;
17use frame_support::weights::WeightToFee;
18use frame_support::{Deserialize, Serialize};
19use frame_system::limits::BlockLength;
20use frame_system::offchain::CreateTransactionBase;
21use pallet_transaction_payment::{
22    Multiplier, NextFeeMultiplier, OnChargeTransaction, TargetedFeeAdjustment,
23};
24use parity_scale_codec::{Codec, Decode, Encode, MaxEncodedLen};
25use scale_info::TypeInfo;
26use sp_core::parameter_types;
27use sp_runtime::traits::{Block as BlockT, Bounded, IdentifyAccount, Verify};
28use sp_runtime::{FixedPointNumber, MultiSignature, Perbill, Perquintill};
29pub use subspace_core_primitives::BlockNumber;
30
31/// Minimum desired number of replicas of the blockchain to be stored by the network,
32/// impacts storage fees.
33pub const MIN_REPLICATION_FACTOR: u16 = 25;
34
35/// The smallest unit of the token is called Shannon.
36pub const SHANNON: Balance = 1;
37/// Subspace Credits have 18 decimal places.
38pub const DECIMAL_PLACES: u8 = 18;
39/// One Subspace Credit.
40pub const SSC: Balance = (10 * SHANNON).pow(DECIMAL_PLACES as u32);
41/// A ratio of `Normal` dispatch class within block, for `BlockWeight` and `BlockLength`.
42pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
43/// 1 in 6 slots (on average, not counting collisions) will have a block.
44/// Must match ratio between block and slot duration in constants above.
45pub const SLOT_PROBABILITY: (u64, u64) = (1, 6);
46/// The block weight for 2 seconds of compute
47pub const BLOCK_WEIGHT_FOR_2_SEC: Weight =
48    Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
49
50/// Maximum block length for non-`Normal` extrinsic is 5 MiB.
51pub const MAX_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
52
53/// Pruning depth multiplier for state and blocks pruning.
54pub const DOMAINS_PRUNING_DEPTH_MULTIPLIER: u32 = 2;
55
56/// Domains Block pruning depth.
57pub const DOMAINS_BLOCK_PRUNING_DEPTH: u32 = 14_400;
58
59/// We allow for 3.75 MiB for `Normal` extrinsic with 5 MiB maximum block length.
60pub fn maximum_normal_block_length() -> BlockLength {
61    BlockLength::max_with_normal_ratio(MAX_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO)
62}
63
64/// The maximum recursion depth we allow when parsing calls.
65/// This is a safety measure to avoid stack overflows.
66///
67/// Deeper nested calls can result in an error, or, if it is secure, the call is skipped.
68/// (Some code does unlimited heap-based recursion via `nested_utility_call_iter()`.)
69pub const MAX_CALL_RECURSION_DEPTH: u32 = 10;
70
71/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
72pub type Signature = MultiSignature;
73
74/// Some way of identifying an account on the chain. We intentionally make it equivalent
75/// to the public key of our transaction signing scheme.
76//
77// Note: sometimes this type alias causes complex trait ambiguity / conflicting implementation errors.
78// As a workaround, `use sp_runtime::AccountId32 as AccountId` instead.
79pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
80
81/// Balance of an account.
82pub type Balance = u128;
83
84/// Index of a transaction in the chain.
85pub type Nonce = u32;
86
87/// A hash of some data used by the chain.
88pub type Hash = sp_core::H256;
89
90/// Type used for expressing timestamp.
91pub type Moment = u64;
92
93/// Type alias for extrinsics.
94pub type ExtrinsicFor<Block> = <Block as BlockT>::Extrinsic;
95
96/// Type alias for block hash.
97pub type BlockHashFor<Block> = <Block as BlockT>::Hash;
98
99/// Type alias for block header.
100pub type HeaderFor<Block> = <Block as BlockT>::Header;
101
102parameter_types! {
103    /// Event segments are disabled on the consensus chain.
104    pub const ConsensusEventSegmentSize: u32 = 0;
105    /// Event segments are enabled on domain chains, this value was derived from benchmarking.
106    pub const DomainEventSegmentSize: u32 = 100;
107}
108
109/// Opaque types.
110///
111/// These are used by the CLI to instantiate machinery that don't need to know the specifics of the
112/// runtime. They can then be made to be agnostic over specific formats of data like extrinsics,
113/// allowing for them to continue syncing the network through upgrades to even the core data
114/// structures.
115pub mod opaque {
116    use super::BlockNumber;
117    use sp_runtime::generic;
118    use sp_runtime::traits::BlakeTwo256;
119    pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
120
121    /// Opaque block header type.
122    pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
123    /// Opaque block type.
124    pub type Block = generic::Block<Header, UncheckedExtrinsic>;
125}
126
127pub mod time {
128    /// Expected block time in milliseconds.
129    ///
130    /// Since Subspace is probabilistic this is the average expected block time that
131    /// we are targeting. Blocks will be produced at a minimum duration defined
132    /// by `SLOT_DURATION`, but some slots will not be allocated to any
133    /// farmer and hence no block will be produced. We expect to have this
134    /// block time on average following the defined slot duration and the value
135    /// of `c` configured for Subspace (where `1 - c` represents the probability of
136    /// a slot being empty).
137    /// This value is only used indirectly to define the unit constants below
138    /// that are expressed in blocks. The rest of the code should use
139    /// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the
140    /// minimum period).
141    ///
142    /// Based on:
143    /// <https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html#-6.-practical-results>
144    pub const MILLISECS_PER_BLOCK: u64 = 6000;
145    /// Approximate number of block in a minute.
146    pub const BLOCKS_IN_AN_MINUTE: u32 = (60 * 1000) / MILLISECS_PER_BLOCK as u32;
147    /// Approximate number of blocks in an hour.
148    pub const BLOCKS_IN_AN_HOUR: u32 = 60 * BLOCKS_IN_AN_MINUTE;
149    /// Approximate number of blocks in a day.
150    pub const BLOCKS_IN_A_DAY: u32 = 24 * BLOCKS_IN_AN_HOUR;
151}
152
153#[derive(Copy, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, MaxEncodedLen, Debug)]
154pub struct CouncilDemocracyConfigParams<BlockNumber> {
155    /// Council motion duration.
156    pub council_motion_duration: BlockNumber,
157    /// Democracy cooloff period.
158    pub democracy_cooloff_period: BlockNumber,
159    /// Democracy enactment period.
160    pub democracy_enactment_period: BlockNumber,
161    /// Fast track voting period.
162    pub democracy_fast_track_voting_period: BlockNumber,
163    /// Launch period.
164    pub democracy_launch_period: BlockNumber,
165    /// Vote locking period.
166    pub democracy_vote_locking_period: BlockNumber,
167    /// Voting period.
168    pub democracy_voting_period: BlockNumber,
169}
170
171impl<BlockNumber: From<u32>> Default for CouncilDemocracyConfigParams<BlockNumber> {
172    fn default() -> Self {
173        Self {
174            council_motion_duration: BLOCKS_IN_A_DAY.into(),
175            democracy_cooloff_period: BLOCKS_IN_A_DAY.into(),
176            democracy_enactment_period: BLOCKS_IN_A_DAY.into(),
177            democracy_fast_track_voting_period: (2 * BLOCKS_IN_A_DAY).into(),
178            democracy_launch_period: (2 * BLOCKS_IN_A_DAY).into(),
179            democracy_vote_locking_period: BLOCKS_IN_A_DAY.into(),
180            democracy_voting_period: BLOCKS_IN_A_DAY.into(),
181        }
182    }
183}
184
185impl<BlockNumber: From<u32>> CouncilDemocracyConfigParams<BlockNumber> {
186    /// Production params for Council democracy config.
187    pub fn production_params() -> Self {
188        Self::default()
189    }
190
191    /// Fast period params for Council democracy config.
192    pub fn fast_params() -> Self {
193        Self {
194            council_motion_duration: (15 * BLOCKS_IN_AN_MINUTE).into(),
195            democracy_cooloff_period: (5 * BLOCKS_IN_AN_MINUTE).into(),
196            democracy_enactment_period: (15 * BLOCKS_IN_AN_MINUTE).into(),
197            democracy_fast_track_voting_period: (5 * BLOCKS_IN_AN_MINUTE).into(),
198            democracy_launch_period: (15 * BLOCKS_IN_AN_MINUTE).into(),
199            democracy_vote_locking_period: BLOCKS_IN_AN_MINUTE.into(),
200            democracy_voting_period: (15 * BLOCKS_IN_AN_MINUTE).into(),
201        }
202    }
203}
204
205/// A trait for determining whether rewards are enabled or not
206pub trait RewardsEnabled {
207    /// Determine whether rewards are enabled or not
208    fn rewards_enabled() -> bool;
209}
210
211/// A trait for finding the address for a block reward based on the `PreRuntime` digests contained within it.
212pub trait FindBlockRewardAddress<RewardAddress> {
213    /// Find the address for a block rewards based on the pre-runtime digests.
214    fn find_block_reward_address() -> Option<RewardAddress>;
215}
216
217/// A trait for finding the addresses for voting reward based on transactions found in the block.
218pub trait FindVotingRewardAddresses<RewardAddress> {
219    /// Find the addresses for voting rewards based on transactions found in the block.
220    fn find_voting_reward_addresses() -> Vec<RewardAddress>;
221}
222
223pub trait StorageFee<Balance> {
224    /// Return the consensus transaction byte fee.
225    fn transaction_byte_fee() -> Balance;
226
227    /// Note the charged storage fee.
228    fn note_storage_fees(fee: Balance);
229}
230
231parameter_types! {
232    /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less
233    /// than this will decrease the weight and more will increase.
234    pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(50);
235    /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to
236    /// change the fees more rapidly.
237    pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(75, 1_000_000);
238    /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure
239    /// that combined with `AdjustmentVariable`, we can recover from the minimum.
240    /// See `multiplier_can_grow_from_zero`.
241    pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10u128);
242    /// The maximum amount of the multiplier.
243    pub MaximumMultiplier: Multiplier = Bounded::max_value();
244}
245
246/// Parameterized slow adjusting fee updated based on
247/// <https://research.web3.foundation/Polkadot/overview/token-economics#2-slow-adjusting-mechanism>
248pub type SlowAdjustingFeeUpdate<R, TargetBlockFullness> = TargetedFeeAdjustment<
249    R,
250    TargetBlockFullness,
251    AdjustmentVariable,
252    MinimumMultiplier,
253    MaximumMultiplier,
254>;
255
256#[derive(Encode, Decode, TypeInfo)]
257pub struct BlockTransactionByteFee<Balance: Codec> {
258    // The value of `transaction_byte_fee` for the current block
259    pub current: Balance,
260    // The value of `transaction_byte_fee` for the next block
261    pub next: Balance,
262}
263
264impl<Balance: Codec + tokens::Balance> Default for BlockTransactionByteFee<Balance> {
265    fn default() -> Self {
266        BlockTransactionByteFee {
267            current: Balance::max_value(),
268            next: Balance::max_value(),
269        }
270    }
271}
272
273parameter_types! {
274    pub const XdmFeeMultipler: u32 = 5;
275}
276
277/// Balance type pointing to the OnChargeTransaction trait.
278pub type OnChargeTransactionBalance<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as OnChargeTransaction<
279    T,
280>>::Balance;
281
282/// Adjusted XDM Weight to fee Conversion.
283pub struct XdmAdjustedWeightToFee<T>(PhantomData<T>);
284impl<T: pallet_transaction_payment::Config> WeightToFee for XdmAdjustedWeightToFee<T> {
285    type Balance = OnChargeTransactionBalance<T>;
286
287    fn weight_to_fee(weight: &Weight) -> Self::Balance {
288        // the adjustable part of the fee.
289        let unadjusted_weight_fee = pallet_transaction_payment::Pallet::<T>::weight_to_fee(*weight);
290        let multiplier = NextFeeMultiplier::<T>::get();
291        // final adjusted weight fee.
292        multiplier.saturating_mul_int(unadjusted_weight_fee)
293    }
294}
295
296#[derive(
297    PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, Ord, PartialOrd, Copy, Debug,
298)]
299pub enum HoldIdentifier {
300    DomainStaking,
301    DomainInstantiation,
302    DomainStorageFund,
303    MessengerChannel,
304    Preimage,
305}
306
307/// Interface for creating an unsigned general extrinsic
308pub trait CreateUnsigned<LocalCall>: CreateTransactionBase<LocalCall> {
309    /// Create an unsigned extrinsic.
310    fn create_unsigned(call: Self::RuntimeCall) -> Self::Extrinsic;
311}
312
313#[cfg(feature = "testing")]
314pub mod tests_utils {
315    use frame_support::dispatch::DispatchClass;
316    use frame_support::weights::Weight;
317    use frame_system::limits::BlockWeights;
318    use pallet_transaction_payment::{Multiplier, MultiplierUpdate};
319    use sp_runtime::traits::{Convert, Get};
320    use sp_runtime::BuildStorage;
321    use std::marker::PhantomData;
322
323    pub struct FeeMultiplierUtils<Runtime, BlockWeightsGetter>(
324        PhantomData<(Runtime, BlockWeightsGetter)>,
325    );
326
327    impl<Runtime, BlockWeightsGetter> FeeMultiplierUtils<Runtime, BlockWeightsGetter>
328    where
329        Runtime: frame_system::Config + pallet_transaction_payment::Config,
330        BlockWeightsGetter: Get<BlockWeights>,
331    {
332        fn max_normal() -> Weight {
333            let block_weights = BlockWeightsGetter::get();
334            block_weights
335                .get(DispatchClass::Normal)
336                .max_total
337                .unwrap_or(block_weights.max_block)
338        }
339
340        fn min_multiplier() -> Multiplier {
341            <Runtime as pallet_transaction_payment::Config>::FeeMultiplierUpdate::min()
342        }
343
344        fn target() -> Weight {
345            <Runtime as pallet_transaction_payment::Config>::FeeMultiplierUpdate::target()
346                * Self::max_normal()
347        }
348
349        // update based on runtime impl.
350        fn runtime_multiplier_update(fm: Multiplier) -> Multiplier {
351            <Runtime as pallet_transaction_payment::Config>::FeeMultiplierUpdate::convert(fm)
352        }
353
354        fn run_with_system_weight<F>(w: Weight, assertions: F)
355        where
356            F: Fn(),
357        {
358            let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
359                .build_storage()
360                .unwrap()
361                .into();
362            t.execute_with(|| {
363                frame_system::Pallet::<Runtime>::set_block_consumed_resources(w, 0);
364                assertions()
365            });
366        }
367
368        // The following function is taken from test with same name from
369        // https://github.com/paritytech/polkadot-sdk/blob/91851951856b8effe627fb1d151fe336a51eef2d/substrate/bin/node/runtime/src/impls.rs#L234
370        // with some small surface changes.
371        pub fn multiplier_can_grow_from_zero()
372        where
373            Runtime: pallet_transaction_payment::Config,
374            BlockWeightsGetter: Get<BlockWeights>,
375        {
376            // if the min is too small, then this will not change, and we are doomed forever.
377            // the block ref time is 1/100th bigger than target.
378            Self::run_with_system_weight(
379                Self::target().set_ref_time((Self::target().ref_time() / 100) * 101),
380                || {
381                    let next = Self::runtime_multiplier_update(Self::min_multiplier());
382                    assert!(
383                        next > Self::min_multiplier(),
384                        "{:?} !> {:?}",
385                        next,
386                        Self::min_multiplier()
387                    );
388                },
389            );
390
391            // the block proof size is 1/100th bigger than target.
392            Self::run_with_system_weight(
393                Self::target().set_proof_size((Self::target().proof_size() / 100) * 101),
394                || {
395                    let next = Self::runtime_multiplier_update(Self::min_multiplier());
396                    assert!(
397                        next > Self::min_multiplier(),
398                        "{:?} !> {:?}",
399                        next,
400                        Self::min_multiplier()
401                    );
402                },
403            )
404        }
405    }
406}