A Substrate pallet to add/remove validators using extrinsics, in Substrate PoA networks.
Note: Current build is compatible with Substrate v2.0.0 release.
To see this pallet in action in a Substrate runtime, watch this video - https://www.youtube.com/watch?v=lIYxE-tOAdw
- Add the module's dependency in the
Cargo.toml
of your runtime directory. Make sure to enter the correct path or git url of the pallet as per your setup.
[dependencies.substrate_validator_set]
package = 'substrate-validator-set'
git = 'https://github.com/gautamdhameja/substrate-validator-set.git'
default-features = false
-
Make sure that you also have the Substrate session pallet as part of your runtime. This is because the validator-set pallet is based on the session pallet.
-
Declare the pallet in your
runtime/src/lib.rs
.
pub use validatorset;
impl validatorset::Trait for Runtime {
type Event = Event;
}
- Also, declare the session pallet in your
runtime/src/lib.rs
. The type configuration of session pallet would depend on the ValidatorSet pallet as shown below.
impl session::Trait for Runtime {
type SessionHandler = <opaque::SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type ShouldEndSession = ValidatorSet;
type SessionManager = ValidatorSet;
type Event = Event;
type Keys = opaque::SessionKeys;
type NextSessionRotation = ValidatorSet;
type ValidatorId = <Self as system::Trait>::AccountId;
type ValidatorIdOf = validatorset::ValidatorOf<Self>;
type DisabledValidatorsThreshold = ();
type WeightInfo = ();
}
- Add both
session
andvalidatorset
pallets inconstruct_runtime
macro. Make sure to add them beforeAura
andGrandpa
pallets.
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
...
Session: session::{Module, Call, Storage, Event, Config<T>},
ValidatorSet: validatorset::{Module, Call, Storage, Event<T>, Config<T>},
Aura: aura::{Module, Config<T>, Inherent(Timestamp)},
Grandpa: grandpa::{Module, Call, Storage, Config, Event},
...
...
}
);
- Add genesis config in the
chain_spec.rs
file forsession
andvalidatorset
pallets, and update it forAura
andGrandpa
pallets. Because the validators are provided by thesession
pallet, we do not initialize them explicitly forAura
andGrandpa
pallets.
fn testnet_genesis(initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool) -> GenesisConfig {
GenesisConfig {
...,
validatorset: Some(ValidatorSetConfig {
validators: initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
}),
session: Some(SessionConfig {
keys: initial_authorities.iter().map(|x| {
(x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone()))
}).collect::<Vec<_>>(),
}),
aura: Some(AuraConfig {
authorities: vec![],
}),
grandpa: Some(GrandpaConfig {
authorities: vec![],
}),
...
}
}
- Make sure you have the same number and order of session keys for your runtime. First in
runtime/src/lib.rs
:
pub struct SessionKeys {
pub aura: Aura,
pub grandpa: Grandpa,
}
- And then in
src/chain_spec.rs
:
fn session_keys(
aura: AuraId,
grandpa: GrandpaId,
) -> SessionKeys {
SessionKeys { aura, grandpa }
}
pub fn get_authority_keys_from_seed(seed: &str) -> (
AccountId,
GrandpaId,
AuraId
) {
(
get_account_id_from_seed::<sr25519::Public>(seed),
get_from_seed::<GrandpaId>(seed),
get_from_seed::<AuraId>(seed)
)
}
cargo build --release
and thencargo run --release -- --dev
The usage of this pallet are demonstrated in the Substrate permissioning sample.
{
"Keys": "SessionKeys2"
}
This code not audited and reviewed for production use cases. You can expect bugs and security vulnerabilities. Do not use it as-is in real applications.