subspace_runtime_primitives/
lib.rs

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