What are the macros #[pallet::genesis_config] and #[pallet::genesis_build] doing on the sudo pallet? - substrate

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// The `AccountId` of the sudo key.
pub key: T::AccountId,
}
#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self { key: Default::default() }
}
}
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
<Key<T>>::put(&self.key);
}
}
What is happening here with genesis_config and genesis_build macros here? Some reading seemed to suggest that implement the trait GenesisBuild<T,I = ()> but I am confused as the docs read: "T and I are placeholder for pallet trait and pallet instance."
What are pallet instances? I also assume pallet trait means the Config trait for the sudo pallet. Is it some how related to configuring a unique StorageValue for the Genesis block so that each instance of a running node can verify that the same Account is Root? Can someone help break it down for me.

What are pallet instances?
Pallets can be made instantiable. This means a Pallet can be used multiple times in a runtime. Each instance will use the same code (modulo different configuration through the configuration trait), but the storage will be different for each instance.
See: https://docs.substrate.io/how-to-guides/v3/basics/instantiable-pallets/
I also assume pallet trait means the Config trait for the sudo pallet. Is it some how related to configuring a unique StorageValue for the Genesis block so that each instance of a running node can verify that the same Account is Root? Can someone help break it down for me.
Yes Pallet trait means the Config trait.
The point here with GenesisBuild taking two generic arguments is to support all kinds of Pallets. Every Pallet is configurable through the trait, so the GenesisBuild trait needs to take the Config generic parameter T. Some Pallets can be instantiable, so it also needs to take I.
This all boils down to some Rust "quirks" to support instantiable Pallets that are using the default instance and custom instances and also to support Pallets that don't use any instancing at all.

#[pallet::genesis_build] implements the trait sp_runtime::BuildModuleGenesisStorage which puts the initial state into the pallet's storage at genesis time.
(The pallet can put state into child storage also at that point.)
The pub enum/struct with #[pallet::genesis_config] holds the fields that genesis_build reads in order to set up the storage. For example there may be investors at genesis that need a vesting schedule set up (See the vesting pallet: https://github.com/paritytech/substrate/blob/3cdb30e1ecbafe8a866317d4550c921b4d686869/frame/vesting/src/lib.rs#L231 ). So for the sudo pallet, the genesis_config struct holds the root key which is set here:
GenesisConfig {
sudo: SudoConfig {
// Assign network admin rights.
key: root_key,
},
...
}
( https://github.com/paritytech/substrate/blob/3cdb30e1ecbafe8a866317d4550c921b4d686869/bin/node-template/node/src/chain_spec.rs#L150 )
Docs for genesis_config are here: https://docs.substrate.io/rustdocs/latest/frame_support/attr.pallet.html#genesis-config-palletgenesis_config-optional

Related

Convert storage macro from frame v1 to frame v2

The title is very descriptive.
I would like to convert this:
decl_storage! {
trait Store for Module<T: Config> as SimpleTreasury {
// No storage items of our own, but we still need decl_storage to initialize the pot
}
add_extra_genesis {
build(|_config| {
// Create the charity's pot of funds, and ensure it has the minimum required deposit
let _ = T::Currency::make_free_balance_be(
&<Module<T>>::account_id(),
T::Currency::minimum_balance(),
);
});
}
}
into frame V2. Below I have my converted version but it seems not working, the minimum balance seems not being set correctly.
#[pallet::genesis_config]
#[derive(Default)]
pub struct GenesisConfig {
}
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig {
fn build(&self) {
let _ = T::Currency::make_free_balance_be(
&<Module<T>>::account_id(),
T::Currency::minimum_balance(),
);
}
}
Can somebody take a look and tell me what's wrong. I would really appreciate it.
Pallet Github link: https://github.com/herou/recipes/tree/recipes_pallet_v2/pallets/charity
Note: Some tests are failing
The pallet macro has a section about upgrading from decl_* macros: https://substrate.dev/rustdocs/latest/frame_support/attr.pallet.html#upgrade-guidelines
I advise to read carefully the section.
To say few points of this doc I can say:
there is a helper inside decl_storage to generate some code for the new pallet macro. By running the macro expansion with the environment variable PRINT_PALLET_UPGRADE: e.g. PRINT_PALLET_UPGRADE=1 cargo check -p $my_pallet$.
The pallet prefix that the storage use is configured differently: in decl_storage the pallet prefix is given (e.g. SimpleTreasury in your example). Now the pallet prefix is the name configured when constructing the runtime. (e.g. in construct_runtime call, when it is written: MyPalletName: path_to_pallet::{Call, ...},, the name MyPalletName). If the name are different you can use some utility function to create a migration: https://substrate.dev/rustdocs/latest/frame_support/storage/migration/index.html
The attributes config() and build() that put specific values into the storage should now be put into the GenesisConfig::build implementation.
Usually the hashers and types to use when declaring the storage should be quite straightforward. But people must be careful about the QueryKind generic. If the storage was written with a value Option<$Something> then the querykind is an OptionQuery, otherwise it is a ValueQuery. (but the helper with PRINT_PALLET_UPGRADE must give you the correct translation.)

Unknown types found, no types for DepartmentDetails

I am trying to use struct in substrate
#[derive(PartialEq, Eq, PartialOrd, Ord, Default, Clone, Encode, Decode, RuntimeDebug)]
pub struct DepartmentDetails {
pub name: Vec<u8>,
pub location: Vec<u8>,
pub details: Vec<u8>,
pub departmentid: u128,
}
In decl_stroage
Department get(fn department_name): map hasher(blake2_128_concat) u128 => DepartmentDetails;
Though node runs successfully without error, it give error with polkadotjs app, saying:
Unknown types found, no types for DepartmentDetails
https://substrate.dev/recipes/structs.html
Polkadot-js can only construct and display types that it understands.
See the FAQ here.
For development you can add custom type descriptions in the Settings > Developer tab.
For production you can add type descriptions to your polkadot-js based UI via extending the types as described here.

Substrate: How to validate the originator of unsigned extrinsics?

I need to be able to identify the source of an unsigned extrinsic for spam prevention purposes. Assume there is a set of known authorities from whom I am willing to accept an unsigned extrinsic. I want to check that the sender of the unsigned extrinsic is a member of this authority set (and that they are who they say they are).
From what I can tell there are a couple of different approaches and I would like to better understand the differences between each and the trade-offs involved.
Add a signature as a call parameter and define ValidateUnsigned.
This approach is used in the ImOnline pallet. Roughly speaking:
decl_module!(
// ...
fn my_unsigned_call(_origin,
args: MyArgs<T>,
authority: T::Authority,
signature: T::Signature) {
// Handle the call
todo!()
}
)
impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
// ...
fn validate_unsigned(
_source: TransactionSource,
call: &Self::Call,
) -> TransactionValidity {
if let Call::my_unsigned_call(args, authority, signature) = call {
// Check the sender is in the approved authority set and verify sig
todo!();
}
}
}
Implement SignedExtension for some metadata associated with the pallet trait. This is touched upon in the docs and seems to be implemented in the TransactionPayment pallet. Implementation would be something like this:
struct SenderInfo<T> {
authority: T::Authority,
signature: T::Signature,
}
impl<T: Config + Send + Sync> SignedExtension for SenderInfo<T>
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>,
{
// ...
fn validate_unsigned(
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize
) -> TransactionValidity {
// validate self.authority and self.signature
}
}
This SignedExtension then needs to be aggregated into the SignedExtra of the runtime. (Right?)
I am tending towards using the second option since it seems cleaner: it doesn't require me to pollute my method signatures with extra information that is not even used in the method call. But would this mean that any transaction submitted to the runtime, signed or unsigned, would need to add this customised SignedExtra?
Are there any other considerations I should be aware of?
I'm working on a very similar thing.
I was able to do so with your approach 1.
Basically I do check two things there:
If payload was signed properly - When you think about it, this will tell you only about the user, but it doesn't check if a user is your authority user.
I do check if this account is on my authorities list
My working example is available here https://github.com/korzewski/jackblock/blob/master/pallets/jackblock/src/lib.rs#L401
Although, this is not perfect because I need to keep a second list of Authorities and add them manually.
Currently I'm trying to refactor it, so my authorities accounts are the same as my validators (Aura pallet). Still looking for a solution so maybe you know how to solve it? Basically how to reuse Aura pallet in my own pallet

How do I constrain associated types on a non-owned trait? [duplicate]

I have this code:
extern crate serde;
use serde::de::DeserializeOwned;
use serde::Serialize;
trait Bar<'a, T: 'a>
where
T: Serialize,
&'a T: DeserializeOwned,
{
}
I would like to write this using an associated type, because the type T is unimportant to the users of this type. I got this far:
trait Bar {
type T: Serialize;
}
I cannot figure out how to specify the other bound.
Ultimately, I want to use a function like this:
extern crate serde_json;
fn test<I: Bar>(t: I::T) -> String {
serde_json::to_string(&t).unwrap()
}
The "correct" solution is to place the bounds on the trait, but referencing the associated type. In this case, you can also use higher ranked trait bounds to handle the reference:
trait Bar
where
Self::T: Serialize,
// ^^^^^^^ Bounds on an associated type
for<'a> &'a Self::T: DeserializeOwned,
// ^^^^^^^^^^^ Higher-ranked trait bounds
{
type T;
}
However, this doesn't work yet.
I believe that you will need to either:
wait for issue 20671 and/or issue 50346 to be fixed.
wait for the generic associated types feature which introduces where clauses on associated types.
In the meantime, the workaround is to duplicate the bound everywhere it's needed:
fn test<I: Bar>(t: I::T) -> String
where
for<'a> &'a I::T: DeserializeOwned,
{
serde_json::to_string(&t).unwrap()
}

Cannot use Rayon's `.par_iter()`

I have a struct which implements Iterator and it works fine as an iterator. It produces values, and using .map(), I download each item from a local HTTP server and save the results. I now want to parallelize this operation, and Rayon looks friendly.
I am getting a compiler error when trying to follow the example in the documentation.
This is the code that works sequentially. generate_values returns the struct which implements Iterator. dl downloads the values and saves them (i.e. it has side effects). Since iterators are lazy in Rust, I have put a .count() at the end so that it will actually run it.
generate_values(14).map(|x| { dl(x, &path, &upstream_url); }).count();
Following the Rayon example I tried this:
generate_values(14).par_iter().map(|x| { dl(x, &path, &upstream_url); }).count();
and got the following error:
src/main.rs:69:27: 69:37 error: no method named `par_iter` found for type `MyIterator` in the current scope
Interestingly, when I use .iter(), which many Rust things use, I get a similar error:
src/main.rs:69:27: 69:33 error: no method named `iter` found for type `MyIterator` in the current scope
src/main.rs:69 generate_values(14).iter().map(|tile| { dl_tile(tile, &tc_path, &upstream_url); }).count();
Since I implement Iterator, I should get .iter() for free right? Is this why .par_iter() doesn't work?
Rust 1.6 and Rayon 0.3.1
$ rustc --version
rustc 1.6.0 (c30b771ad 2016-01-19)
Rayon 0.3.1 defines par_iter as:
pub trait IntoParallelRefIterator<'data> {
type Iter: ParallelIterator<Item=&'data Self::Item>;
type Item: Sync + 'data;
fn par_iter(&'data self) -> Self::Iter;
}
There is only one type that implements this trait in Rayon itself: [T]:
impl<'data, T: Sync + 'data> IntoParallelRefIterator<'data> for [T] {
type Item = T;
type Iter = SliceIter<'data, T>;
fn par_iter(&'data self) -> Self::Iter {
self.into_par_iter()
}
}
That's why Lukas Kalbertodt's answer to collect to a Vec will work; Vec dereferences to a slice.
Generally, Rayon could not assume that any iterator would be amenable to parallelization, so it cannot default to including all Iterators.
Since you have defined generate_values, you could implement the appropriate Rayon trait for it as well:
IntoParallelIterator
IntoParallelRefIterator
IntoParallelRefMutIterator
That should allow you to avoid collecting into a temporary vector.
No, the Iterator trait has nothing to do with the iter() method. Yes, this is slightly confusing.
There are a few different concepts here. An Iterator is a type that can spit out values; it only needs to implement next() and has many other methods, but none of these is iter(). Then there is IntoIterator which says that a type can be transformed into an Iterator. This trait has the into_iter() method. Now the iter() method is not really related to any of those two traits. It's just a normal method of many types, that often works similar to into_iter().
Now to your Rayon problem: it looks like you can't just take any normal iterator and turn it into a parallel one. However, I never used this library, so takes this with a grain of salt. To me it looks like you need to collect your iterator into a Vec to be able to use par_iter().
And just as a note: when using normal iterators, you shouldn't use map() and count(), but rather use a standard for loop.

Resources