This video demonstrates how to add a new validator in a Substrate PoA network using the ValidatorSet pallet.
A Substrate pallet to add/remove validators using extrinsics, in Substrate PoA networks.
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;
}
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 = ();
}
session
and validatorset
pallets in construct_runtime
macro. Make sure to add them before Aura
and Grandpa
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},
...
...
}
);
chain_spec.rs
file for session
and validatorset
pallets, and update it for Aura
and Grandpa
pallets. Because the validators are provided by the session
pallet, we do not initialize them explicitly for Aura
and Grandpa
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![],
}),
...
}
}
runtime/src/lib.rs
:pub struct SessionKeys {
pub aura: Aura,
pub grandpa: Grandpa,
}
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 then cargo 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.
Source Code:
ValidatorSet Pallet: https://github.com/gautamdhameja/substrate-validator-set
Permissioning Sample: https://github.com/gautamdhameja/substrate-permissioning
#substrate #poa #blockchain