Newer
Older
/// }
///
/// #[pallet::inherent]
/// impl<T: Config<I>, I: 'static> ProvideInherent for Pallet<T, I> {
/// type Call = Call<T, I>;
/// type Error = InherentError;
///
/// const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
///
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
/// unimplemented!();
/// }
///
/// fn is_inherent(_call: &Self::Call) -> bool {
/// unimplemented!();
/// }
/// }
///
/// // Regular rust code needed for implementing ProvideInherent trait
///
/// #[derive(codec::Encode, sp_runtime::RuntimeDebug)]
/// #[cfg_attr(feature = "std", derive(codec::Decode))]
/// pub enum InherentError {
/// }
///
/// impl sp_inherents::IsFatalError for InherentError {
/// fn is_fatal_error(&self) -> bool {
/// unimplemented!();
/// }
/// }
///
/// pub const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"testpall";
/// }
/// ```
///
Sam Johnson
committed
/// # Upgrade guidelines
/// 1. Export the metadata of the pallet for later checks
/// - run your node with the pallet active
/// - query the metadata using the `state_getMetadata` RPC and curl, or use `subsee -p
/// <PALLET_NAME> > meta.json`
Sam Johnson
committed
/// 2. Generate the template upgrade for the pallet provided by `decl_storage` with the
/// environment variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p
/// my_pallet`. This template can be used as it contains all information for storages,
/// genesis config and genesis build.
Sam Johnson
committed
/// 3. Reorganize the pallet to have the trait `Config`, `decl_*` macros,
/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`),
/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`), and Origin` all together in one
/// file. Suggested order:
Sam Johnson
committed
/// * `Config`,
/// * `decl_module`,
/// * `decl_event`,
/// * `decl_error`,
/// * `decl_storage`,
/// * `origin`,
/// * `validate_unsigned`,
/// * `provide_inherent`, so far it should compile and all be correct.
/// 4. start writing the new pallet module
/// ```ignore
/// pub use pallet::*;
///
/// #[frame_support::pallet]
/// pub mod pallet {
/// use frame_support::pallet_prelude::*;
/// use frame_system::pallet_prelude::*;
/// use super::*;
///
/// #[pallet::pallet]
/// #[pallet::generate_store($visibility_of_trait_store trait Store)]
/// // NOTE: if the visibility of trait store is private but you want to make it available
/// // in super, then use `pub(super)` or `pub(crate)` to make it available in crate.
thiolliere
committed
/// pub struct Pallet<T>(_);
/// // pub struct Pallet<T, I = ()>(PhantomData<T>); // for instantiable pallet
/// }
/// ```
/// 5. **migrate Config**: move trait into the module with
Sam Johnson
committed
/// * all const in `decl_module` to [`#[pallet::constant]`](#palletconstant)
/// * add the bound `IsType<<Self as frame_system::Config>::RuntimeEvent>` to `type
/// RuntimeEvent`
/// 7. **migrate decl_module**: write:
/// ```ignore
/// #[pallet::hooks]
/// impl<T: Config> Hooks for Pallet<T> {
/// }
/// ```
Sam Johnson
committed
/// and write inside `on_initialize`, `on_finalize`, `on_runtime_upgrade`,
/// `offchain_worker`, and `integrity_test`.
///
/// then write:
/// ```ignore
/// #[pallet::call]
/// }
/// ```
Sam Johnson
committed
/// and write inside all the calls in `decl_module` with a few changes in the signature:
/// - origin must now be written completely, e.g. `origin: OriginFor<T>`
/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you
/// might need to put `Ok(().into())` at the end or the function.
/// - `#[compact]` must now be written
/// [`#[pallet::compact]`](#palletcompact-some_arg-some_type)
/// - `#[weight = ..]` must now be written [`#[pallet::weight(..)]`](#palletweightexpr)
///
/// 7. **migrate event**: rewrite as a simple enum with the attribute
/// [`#[pallet::event]`](#event-palletevent-optional), use [`#[pallet::generate_deposit($vis
/// fn deposit_event)]`](#event-palletevent-optional) to generate `deposit_event`,
/// 8. **migrate error**: rewrite it with attribute
/// [`#[pallet::error]`](#error-palleterror-optional).
/// 9. **migrate storage**: `decl_storage` provide an upgrade template (see 3.). All storages,
/// genesis config, genesis build and default implementation of genesis config can be taken
/// from it directly.
Sam Johnson
committed
///
/// Otherwise here is the manual process:
///
/// first migrate the genesis logic. write:
/// ```ignore
/// #[pallet::genesis_config]
/// struct GenesisConfig {
/// // fields of add_extra_genesis
/// }
/// impl Default for GenesisConfig {
/// // type default or default provided for fields
/// }
/// #[pallet::genesis_build]
/// impl<T: Config> GenesisBuild<T> for GenesisConfig {
/// // for instantiable pallet:
/// // `impl<T: Config, I: 'static> GenesisBuild<T, I> for GenesisConfig {
/// fn build() {
/// // The add_extra_genesis build logic
/// }
/// }
/// ```
Sam Johnson
committed
/// for each storage, if it contains `config(..)` then add fields, and make it default to
/// the value in `= ..;` or the type default if none, if it contains no build then also add
/// the logic to build the value. for each storage if it contains `build(..)` then add the
/// logic to `genesis_build`.
///
/// NOTE: within `decl_storage`: the individual config is executed first, followed by the
/// build and finally the `add_extra_genesis` build.
///
/// Once this is done you can migrate storages individually, a few notes:
/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing,
/// - for storages with `get(fn ..)` use [`#[pallet::getter(fn
/// ...)]`](#palletgetterfn-my_getter_fn_name-optional)
/// - for storages with value being `Option<$something>` make generic `Value` being
/// `$something` and generic `QueryKind` being `OptionQuery` (note: this is default).
/// Otherwise make `Value` the complete value type and `QueryKind` being `ValueQuery`.
/// - for storages with default value: `= $expr;` provide some specific `OnEmpty` generic.
/// To do so use of `#[pallet::type_value]` to generate the wanted struct to put.
/// example: `MyStorage: u32 = 3u32` would be written:
///
/// ```ignore
/// #[pallet::type_value] fn MyStorageOnEmpty() -> u32 { 3u32 }
/// #[pallet::storage]
/// pub(super) type MyStorage<T> = StorageValue<_, u32, ValueQuery, MyStorageOnEmpty>;
Sam Johnson
committed
/// NOTE: `decl_storage` also generates the functions `assimilate_storage` and
/// `build_storage` directly on `GenesisConfig`, and these are sometimes used in tests.
/// In order not to break they can be implemented manually, one can implement those
/// functions by calling the `GenesisBuild` implementation.
/// 10. **migrate origin**: move the origin to the pallet module to be under a
/// [`#[pallet::origin]`](#origin-palletorigin-optional) attribute
/// 11. **migrate validate_unsigned**: move the
/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) implementation to the pallet
/// module under a
/// [`#[pallet::validate_unsigned]`](#validate-unsigned-palletvalidate_unsigned-optional)
/// attribute
/// 12. **migrate provide_inherent**: move the
/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) implementation to the pallet
/// module under a [`#[pallet::inherent]`](#inherent-palletinherent-optional) attribute
/// 13. rename the usage of `Module` to `Pallet` inside the crate.
Sam Johnson
committed
/// 14. migration is done, now double check the migration with the checking migration
/// guidelines shown below.
Sam Johnson
committed
/// # Checking upgrade guidelines:
/// * compare metadata. Use [subsee](https://github.com/ascjones/subsee) to fetch the metadata
Sam Johnson
committed
/// and do a diff of the resulting json before and after migration. This checks for:
/// * call, names, signature, docs
/// * event names, docs
/// * error names, docs
/// * storage names, hasher, prefixes, default value
/// * error, error, constant
/// * manually check that:
Sam Johnson
committed
/// * `Origin` was moved inside the macro under
/// [`#[pallet::origin]`](#origin-palletorigin-optional) if it exists
/// * [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) was moved inside the macro
/// under
/// [`#[pallet::validate_unsigned)]`](#validate-unsigned-palletvalidate_unsigned-optional)
/// if it exists
/// * [`ProvideInherent`](`pallet_prelude::ProvideInherent`) was moved inside the macro
/// under [`#[pallet::inherent)]`](#inherent-palletinherent-optional) if it exists
/// * `on_initialize` / `on_finalize` / `on_runtime_upgrade` / `offchain_worker` were moved
/// to the `Hooks` implementation
/// * storages with `config(..)` were converted to `GenesisConfig` field, and their default
/// is `= $expr;` if the storage has a default value
/// * storages with `build($expr)` or `config(..)` were built in `GenesisBuild::build`
/// * `add_extra_genesis` fields were converted to `GenesisConfig` field with their correct
/// default if specified
/// * `add_extra_genesis` build was written into `GenesisBuild::build`
/// * storage items defined with [`pallet`] use the name of the pallet provided by
Sam Johnson
committed
/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used
/// the `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). Thus
/// a runtime using the pallet must be careful with this change. To handle this change:
/// * either ensure that the name of the pallet given to `construct_runtime!` is the same
/// as the name the pallet was giving to `decl_storage`,
/// * or do a storage migration from the old prefix used to the new prefix used.
///
/// NOTE: The prefixes used by storage items are in metadata. Thus, ensuring the metadata
/// hasn't changed ensures that the `pallet_prefix`s used by the storage items haven't changed.
///
/// # Notes when macro fails to show proper error message spans:
///
/// Rustc loses span for some macro input. Some tips to fix it:
/// * do not use inner attribute:
/// ```ignore
/// #[pallet]
/// pub mod pallet {
/// //! This inner attribute will make span fail
/// ..
/// }
/// ```
/// * use the newest nightly possible.
pub use frame_support_procedural::pallet;
Sam Johnson
committed
/// Contains macro stubs for all of the pallet:: macros
pub mod pallet_macros {
pub use frame_support_procedural::{
call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error,
event, extra_constants, feeless_if, generate_deposit, generate_store, getter, hooks,
import_section, inherent, no_default, no_default_bounds, origin, pallet_section,
storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight,
whitelist_storage,
Sam Johnson
committed
};
/// Allows you to define the genesis configuration for the pallet.
///
/// Item is defined as either an enum or a struct. It needs to be public and implement the
/// trait [`frame_support::traits::BuildGenesisConfig`].
///
/// See [`genesis_build`] for an example.
pub use frame_support_procedural::genesis_config;
/// Allows you to define how the state of your pallet at genesis is built. This
/// takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's initial
/// state.
///
/// The fields of the `GenesisConfig` can in turn be populated by the chain-spec.
///
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
///
/// ```
/// #[frame_support::pallet]
/// pub mod pallet {
/// # #[pallet::config]
/// # pub trait Config: frame_system::Config {}
/// # #[pallet::pallet]
/// # pub struct Pallet<T>(_);
/// # use frame_support::traits::BuildGenesisConfig;
/// #[pallet::genesis_config]
/// #[derive(frame_support::DefaultNoBound)]
/// pub struct GenesisConfig<T: Config> {
/// foo: Vec<T::AccountId>
/// }
///
/// #[pallet::genesis_build]
/// impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
/// fn build(&self) {
/// // use &self to access fields.
/// let foo = &self.foo;
/// todo!()
/// }
/// }
/// }
/// ```
///
/// ## Former Usage
///
/// Prior to <https://github.com/paritytech/substrate/pull/14306>, the following syntax was used.
/// This is deprecated and will soon be removed.
///
/// ```
/// #[frame_support::pallet]
/// pub mod pallet {
/// # #[pallet::config]
/// # pub trait Config: frame_system::Config {}
/// # #[pallet::pallet]
/// # pub struct Pallet<T>(_);
/// # use frame_support::traits::GenesisBuild;
/// #[pallet::genesis_config]
/// #[derive(frame_support::DefaultNoBound)]
/// pub struct GenesisConfig<T: Config> {
/// foo: Vec<T::AccountId>
/// }
///
/// #[pallet::genesis_build]
/// impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
/// fn build(&self) {
/// todo!()
/// }
/// }
/// }
/// ```
pub use frame_support_procedural::genesis_build;
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded
/// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`)
/// into metadata.
///
/// ## Example
///
/// ```
/// #[frame_support::pallet]
/// mod pallet {
/// use frame_support::pallet_prelude::*;
/// # #[pallet::pallet]
/// # pub struct Pallet<T>(_);
/// #[pallet::config]
/// pub trait Config: frame_system::Config {
/// /// This is like a normal `Get` trait, but it will be added into metadata.
/// #[pallet::constant]
/// type Foo: Get<u32>;
/// }
/// }
/// ```
pub use frame_support_procedural::constant;
/// Declares a type alias as a storage item. Storage items are pointers to data stored
/// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on
/// the type of the storage.
///
/// > From the perspective of this pallet, the entire blockchain state is abstracted behind
/// > a key-value api, namely [`sp_io::storage`].
///
/// ## Storage Types
///
/// The following storage types are supported by the `#[storage]` macro. For specific
/// information about each storage type, refer to the documentation of the respective type.
///
/// * [`StorageValue`](crate::storage::types::StorageValue)
/// * [`StorageMap`](crate::storage::types::StorageMap)
/// * [`CountedStorageMap`](crate::storage::types::CountedStorageMap)
/// * [`StorageDoubleMap`](crate::storage::types::StorageDoubleMap)
/// * [`StorageNMap`](crate::storage::types::StorageNMap)
/// * [`CountedStorageNMap`](crate::storage::types::CountedStorageNMap)
///
/// ## Storage Type Usage
///
/// The following details are relevant to all of the aforementioned storage types.
/// Depending on the exact storage type, it may require the following generic parameters:
///
/// * [`Prefix`](#prefixes) - Used to give the storage item a unique key in the underlying
/// storage.
/// * `Key` - Type of the keys used to store the values,
/// * `Value` - Type of the value being stored,
/// * [`Hasher`](#hashers) - Used to ensure the keys of a map are uniformly distributed,
/// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying
/// storage,
/// * `OnEmpty` - Used to handle missing values when querying the underlying storage,
/// * `MaxValues` - _not currently used_.
///
/// Each `Key` type requires its own designated `Hasher` declaration, so that
/// [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) needs two of
/// each, and [`StorageNMap`](frame_support::storage::types::StorageNMap) needs `N` such
/// pairs. Since [`StorageValue`](frame_support::storage::types::StorageValue) only stores
/// a single element, no configuration of hashers is needed.
///
/// ### Syntax
///
/// Two general syntaxes are supported, as demonstrated below:
///
/// 1. Named type parameters, e.g., `type Foo<T> = StorageValue<Value = u32>`.
/// 2. Positional type parameters, e.g., `type Foo<T> = StorageValue<_, u32>`.
///
/// In both instances, declaring the generic parameter `<T>` is mandatory. Optionally, it
/// can also be explicitly declared as `<T: Config>`. In the compiled code, `T` will
/// automatically include the trait bound `Config`.
///
/// Note that in positional syntax, the first generic type parameter must be `_`.
///
/// #### Example
///
/// ```
/// #[frame_support::pallet]
/// mod pallet {
/// # use frame_support::pallet_prelude::*;
/// # #[pallet::config]
/// # pub trait Config: frame_system::Config {}
/// # #[pallet::pallet]
/// # pub struct Pallet<T>(_);
/// /// Positional syntax, without bounding `T`.
/// #[pallet::storage]
/// pub type Foo<T> = StorageValue<_, u32>;
///
/// /// Positional syntax, with bounding `T`.
/// #[pallet::storage]
/// pub type Bar<T: Config> = StorageValue<_, u32>;
///
/// /// Named syntax.
/// #[pallet::storage]
/// pub type Baz<T> = StorageMap<Hasher = Blake2_128Concat, Key = u32, Value = u32>;
/// }
/// ```
///
/// ### QueryKind
///
/// Every storage type mentioned above has a generic type called
/// [`QueryKind`](frame_support::storage::types::QueryKindTrait) that determines its
/// "query" type. This refers to the kind of value returned when querying the storage, for
/// instance, through a `::get()` method.
///
/// There are three types of queries:
///
/// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type.
/// It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is
/// the value type.
/// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself
/// if present; otherwise, it returns `Default::default()`. This behavior can be
/// adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty =
/// GetDefault`.
/// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result<V, E>`,
/// where `V` is the value type.
///
/// See [`QueryKind`](frame_support::storage::types::QueryKindTrait) for further examples.
///
/// ### Optimized Appending
///
/// All storage items — such as
/// [`StorageValue`](frame_support::storage::types::StorageValue),
/// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an
/// `::append()` method optimized for collections. Using this method avoids the
/// inefficiency of decoding and re-encoding entire collections when adding items. For
/// instance, consider the storage declaration `type MyVal<T> = StorageValue<_, Vec<u8>,
/// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you
/// directly add bytes to the end in storage without processing the full list. Depending on
/// the storage type, additional key specifications may be needed.
///
/// #### Example
#[doc = docify::embed!("src/lib.rs", example_storage_value_append)]
/// Similarly, there also exists a `::try_append()` method, which can be used when handling
/// types where an append operation might fail, such as a
/// [`BoundedVec`](frame_support::BoundedVec).
///
/// #### Example
#[doc = docify::embed!("src/lib.rs", example_storage_value_try_append)]
/// ### Optimized Length Decoding
///
/// All storage items — such as
/// [`StorageValue`](frame_support::storage::types::StorageValue),
/// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts —
/// incorporate the `::decode_len()` method. This method allows for efficient retrieval of
/// a collection's length without the necessity of decoding the entire dataset.
/// #### Example
#[doc = docify::embed!("src/lib.rs", example_storage_value_decode_len)]
/// ### Hashers
///
/// For all storage types, except
/// [`StorageValue`](frame_support::storage::types::StorageValue), a set of hashers needs
/// to be specified. The choice of hashers is crucial, especially in production chains. The
/// purpose of storage hashers in maps is to ensure the keys of a map are
/// uniformly distributed. An unbalanced map/trie can lead to inefficient performance.
///
/// In general, hashers are categorized as either cryptographically secure or not. The
/// former is slower than the latter. `Blake2` and `Twox` serve as examples of each,
/// respectively.
///
/// As a rule of thumb:
///
/// 1. If the map keys are not controlled by end users, or are cryptographically secure by
/// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT
/// required.
/// 2. If the map keys are controllable by the end users, cryptographically secure hashers
/// should be used.
///
/// For more information, look at the types that implement
/// [`frame_support::StorageHasher`](frame_support::StorageHasher).
///
/// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to
/// the implementors section of
/// [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher).
///
/// ### Prefixes
///
/// Internally, every storage type generates a "prefix". This prefix serves as the initial
/// segment of the key utilized to store values in the on-chain state (i.e., the final key
/// used in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule
/// applies:
///
/// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(STORAGE_PREFIX)`,
/// > where
/// > `pallet_prefix` is the name assigned to the pallet instance in
/// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and
/// > `STORAGE_PREFIX` is the name of the `type` aliased to a particular storage type, such
/// > as
/// > `Foo` in `type Foo<T> = StorageValue<..>`.
///
/// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is
/// required. For map types, the prefix is extended with one or more keys defined by the
/// map.
///
/// #### Example
#[doc = docify::embed!("src/lib.rs", example_storage_value_map_prefixes)]
/// ## Related Macros
///
/// The following attribute macros can be used in conjunction with the `#[storage]` macro:
///
/// * [`macro@getter`]: Creates a custom getter function.
/// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item.
/// * [`macro@unbounded`]: Declares the storage item as unbounded.
///
/// #### Example
/// ```
/// #[frame_support::pallet]
/// mod pallet {
/// # use frame_support::pallet_prelude::*;
/// # #[pallet::config]
/// # pub trait Config: frame_system::Config {}
/// # #[pallet::pallet]
/// # pub struct Pallet<T>(_);
/// /// A kitchen-sink StorageValue, with all possible additional attributes.
/// #[pallet::storage]
/// #[pallet::getter(fn foo)]
/// #[pallet::storage_prefix = "OtherFoo"]
/// #[pallet::unbounded]
/// pub type Foo<T> = StorageValue<_, u32, ValueQuery>;
/// }
/// ```
pub use frame_support_procedural::storage;
Sam Johnson
committed
}
#[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")]
pub mod error {
#[doc(hidden)]
pub use sp_runtime::traits::{BadOrigin, LookupError};
}
#[doc(inline)]
pub use frame_support_procedural::register_default_impl;
// Generate a macro that will enable/disable code based on `std` feature being active.
sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $);
// Helper for implementing GenesisBuilder runtime API
pub mod genesis_builder_helper;
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
#[cfg(test)]
mod test {
// use super::*;
use crate::{
hash::*,
storage::types::{StorageMap, StorageValue, ValueQuery},
traits::{ConstU32, StorageInstance},
BoundedVec,
};
use sp_io::{hashing::twox_128, TestExternalities};
struct Prefix;
impl StorageInstance for Prefix {
fn pallet_prefix() -> &'static str {
"test"
}
const STORAGE_PREFIX: &'static str = "foo";
}
struct Prefix1;
impl StorageInstance for Prefix1 {
fn pallet_prefix() -> &'static str {
"test"
}
const STORAGE_PREFIX: &'static str = "MyVal";
}
struct Prefix2;
impl StorageInstance for Prefix2 {
fn pallet_prefix() -> &'static str {
"test"
}
const STORAGE_PREFIX: &'static str = "MyMap";
}
#[docify::export]
#[test]
pub fn example_storage_value_try_append() {
type MyVal = StorageValue<Prefix, BoundedVec<u8, ConstU32<10>>, ValueQuery>;
TestExternalities::default().execute_with(|| {
MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap());
assert_eq!(MyVal::get(), vec![42, 43]);
// Try to append a single u32 to BoundedVec stored in `MyVal`
assert_ok!(MyVal::try_append(40));
assert_eq!(MyVal::get(), vec![42, 43, 40]);
});
}
#[docify::export]
#[test]
pub fn example_storage_value_append() {
type MyVal = StorageValue<Prefix, Vec<u8>, ValueQuery>;
TestExternalities::default().execute_with(|| {
MyVal::set(vec![42, 43]);
assert_eq!(MyVal::get(), vec![42, 43]);
// Append a single u32 to Vec stored in `MyVal`
MyVal::append(40);
assert_eq!(MyVal::get(), vec![42, 43, 40]);
});
}
#[docify::export]
#[test]
pub fn example_storage_value_decode_len() {
type MyVal = StorageValue<Prefix, BoundedVec<u8, ConstU32<10>>, ValueQuery>;
TestExternalities::default().execute_with(|| {
MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap());
assert_eq!(MyVal::decode_len().unwrap(), 2);
});
}
#[docify::export]
#[test]
pub fn example_storage_value_map_prefixes() {
type MyVal = StorageValue<Prefix1, u32, ValueQuery>;
type MyMap = StorageMap<Prefix2, Blake2_128Concat, u16, u32, ValueQuery>;
TestExternalities::default().execute_with(|| {
// This example assumes `pallet_prefix` to be "test"
// Get storage key for `MyVal` StorageValue
assert_eq!(
MyVal::hashed_key().to_vec(),
[twox_128(b"test"), twox_128(b"MyVal")].concat()
);
// Get storage key for `MyMap` StorageMap and `key` = 1
let mut k: Vec<u8> = vec![];
k.extend(&twox_128(b"test"));
k.extend(&twox_128(b"MyMap"));
k.extend(&1u16.blake2_128_concat());
assert_eq!(MyMap::hashed_key_for(1).to_vec(), k);
});
}
}