Skip to content

Permissioned Babe NPoS Runtime#1708

Open
liamaharon wants to merge 233 commits intodevnet-readyfrom
node-decentralization
Open

Permissioned Babe NPoS Runtime#1708
liamaharon wants to merge 233 commits intodevnet-readyfrom
node-decentralization

Conversation

@liamaharon
Copy link
Collaborator

@liamaharon liamaharon commented Jun 2, 2025

Phase 3 in #1887

Now that we have a Hybrid Node that supports seamless Aura to Babe upgrades and block imports, we are finally ready to enact the Aura PoA to Babe NPoS runtime upgrade.

This PR includes

  • Changing the runtime from Aura PoA to Babe NPoS consensus.
  • Logic constraining NPoS participants to a whitelisted set (maintained by root)
  • A Babe NPoS migration which initializes Babe NPoS with authorities from the Aura PoA block which executed the runtime upgrade
  • A new admin-util extrinsic allowing customization of the emission "cut" allocated to NPoS validator
  • Change to run_coinbase to set aside NPoS validator emissions

I have tested upgrades with fresh and baedeker runtimes.

Steps for this PR

  • Review by Greg & Shamil
  • Stand up network we can test it with 3rd parties running validators

Once confirmed no issues with the above, we can merge.

@liamaharon liamaharon marked this pull request as draft June 6, 2025 04:34
@liamaharon liamaharon changed the base branch from hybrid-node to devnet-ready October 1, 2025 23:22
@liamaharon liamaharon force-pushed the node-decentralization branch 5 times, most recently from f054964 to d572164 Compare October 1, 2025 23:44
@liamaharon liamaharon force-pushed the node-decentralization branch from d572164 to 6129f4c Compare October 1, 2025 23:46
@liamaharon liamaharon marked this pull request as ready for review October 2, 2025 00:23
Copy link
Collaborator

@shamil-gadelshin shamil-gadelshin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I tested the runtime upgrade using baedeker tools, and it worked like a charm!

As discussed offline, please, prepare a separate PR for patch->fork migration.

I left a couple of minor comments. I will likely have more review rounds and revisit babe configuration again.

It makes sense to start preparing a test plan using a separate network.

>;
type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
type ForceOrigin = EnsureRoot<Self::AccountId>;
type WeightInfo = ();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, restore all weights. We'll add other weights later.

let next_pending_node_validator_emissions = node_validator_block_emission
.to_num::<u64>()
.saturating_add(PendingNodeValidatorEmissions::<T>::get().into());
PendingNodeValidatorEmissions::<T>::set(next_pending_node_validator_emissions.into());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to receive these emissions? I don't see this infrastructure part.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you plan to introduce it later in the following PRs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emissions are paid at the end of each era. It is already implemented:

pub struct EraPayout;
impl pallet_staking::EraPayout<Balance> for EraPayout {
fn era_payout(
_total_staked: Balance,
_total_issuance: Balance,
_era_duration_millis: u64,
) -> (Balance, Balance) {
let era_emissions = pallet_subtensor::PendingNodeValidatorEmissions::<Runtime>::take();
(era_emissions.into(), 0u64)
}
}

total_block_emission.saturating_sub(node_validator_block_emission);

// Increment pending validator emissions to be paid out at the end of the era.
let next_pending_node_validator_emissions = node_validator_block_emission
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider mutate here?

Copy link
Collaborator Author

@liamaharon liamaharon Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't, what is the benefit?

let keys = SessionKeys {
babe: babe_id.clone(),
grandpa: sr25519_to_ed25519(babe_id.clone())
.expect("Failed to map Babe ID to Grandpa ID")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't have panics in the runtime code.

Copy link
Collaborator Author

@liamaharon liamaharon Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this situation we actually want to runtime to panic, because we do not want the chain to continue with a misconfigured / accidental set of Babe authorities.

Furthermore, we have try-runtime checks to ensure we have not misconfigured this mapping. If the .expect triggers, it means some very bad undefined behavior is occurring that must be investigated manually.

The alternative would be to brick it without a panic (e.g. not setting any authorities), but I think a panic is the most obvious way to call to our attention somehow the authorities are misconfigured.

Happy to discuss if you have any better ideas how to proceed in this scenario.

.saturating_add(<T as frame_system::Config>::DbWeight::get().writes(1))
.saturating_add(<T as frame_system::Config>::DbWeight::get().reads(0_u64)),
DispatchClass::Operational,
Pays::No
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pays::Yes

Copy link
Collaborator Author

@liamaharon liamaharon Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should sudo account pay? Also why have this be Pays::Yes and the rest of the admin utils use Pays::No?

@liamaharon liamaharon force-pushed the node-decentralization branch from e39c3e5 to b40af33 Compare October 20, 2025 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants