In the Permissioned Network tutorial on Substrate docs, it's shown how to created a permissioned network from scratch along with the node-authorization pallet to manage the validator set.

However, in the "Add genesis storage for authorized nodes" section it's said that some pre-genesis configuration is required.

Is it possible to add this pallet to a permissioned network after it's started?

  • 1
    I'm pretty sure that you can run a forkless upgrade with this pallet, but you won't be able to set your authorized nodes. The node-authorization pallet uses the genesis config to insert authorized nodes, so if the genesis config is missing, in case the upgrade works, you will have 0 authorized nodes, therefore breaking the chain.
    – andresvsm
    Jul 19, 2022 at 6:46
  • @andresvsm thanks for the answer. What would be the correct way to add more validators to a PoA chain after genesis? (since bootnodes are recorded in the chain-spec as well)
    – afm
    Jul 19, 2022 at 14:57
  • Great answers, make sure you test locally before you go live with this.
    – Bruno
    Jul 19, 2022 at 23:17
  • @afm I had the same issue, I haven't tried Shawn Tabrizi's answer, but instead I used the validator-set pallet (github.com/gautamdhameja/substrate-validator-set), combined with the im-online and session pallet to remove automatically offline nodes. But to be honest, you can remove the node-authorization pallet and work only with the validator-set. Combining both allows you to control read-access (node-authorization) and write-access (validator-set)
    – andresvsm
    Jul 20, 2022 at 5:41
  • @andresvsm but in the end you managed to do it without adding the pallets at genesis first? Or you had to re-start?
    – afm
    Jul 20, 2022 at 17:36

2 Answers 2


I am not sure if your node will break including the pallet without a genesis, but there are a few functions like:

/// Reset all the well known nodes. This will not remove the ownership and additional
/// connections for the removed nodes. The node owner can perform further cleaning if
/// they decide to leave the network.
/// May only be called from `T::ResetOrigin`.
/// - `nodes`: the new nodes for the allow list.
#[pallet::weight((T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational))]
pub fn reset_well_known_nodes(
    origin: OriginFor<T>,
    nodes: Vec<(PeerId, T::AccountId)>,
) -> DispatchResult {
    ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::<T>::TooManyNodes);


    Self::deposit_event(Event::NodesReset { nodes });

Which allow you to initialize or set into storage the nodes you want to use.

If not having the genesis would break the chain, there are three ways forward:

  1. Install this pallet into your runtime, but do not actually configure it to control the nodes on your network. Instead, use whatever the existing system you have is, and just stick it in there to do nothing. Then you can add the nodes you want via these calls.

  2. Use a runtime migration in the runtime upgrade to set the expected nodes you would otherwise set in genesis. It should basically be easy enough to call the genesis initialization at the beginning of any new block via on_runtime_upgrade.

  3. Use a call like set_storage to set the storage for the validator nodes where the pallet would expect to find them. You can do this before the pallet is ever added to your chain, and then, as soon as it is added, the data is already there. This is similar to a runtime migration, but done beforehand instead of on the fly.

End of the day, storage is just storage. Genesis initialization is just setting values into storage, and then the pallet can read and use those values. You can set those storage values a million different ways, and the pallet will work just fine.


I wrote a customized version of node-authorization as an answer to this question. It's just a PoC and not production-ready.

It adds a storage migration so that it can be used on a chain after Genesis. The storage migration adds Alice and Bob as Well-Known nodes after the runtime upgrade. That way, the "Authorize specific nodes" tutorial can be followed while skipping the Genesis step.

Another modification that proved necessary was adding a check to the offchain worker so that it only calls set_authorized_nodes if storage has already been populated. Otherwise, the chain bricks after the runtime upgrade.

  • Can you help is adding substrate-validator-set pallet after Genesis? Jan 10 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.