Now that the PoA is running with multiple Aura validators in my substrate-node-template. How could I configure that reward amount or value for my validators?
4 Answers
I got it working, PoA will reward the validator who created the block using the tip as the sample value for the fees, here are the steps:
- Install the pallet_authorship
pallet-authorship = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.23" }
- Configure the pallet to get the current author of the block
pub struct AuraAccountAdapter;
impl frame_support::traits::FindAuthor<AccountId> for AuraAccountAdapter {
fn find_author<'a, I>(digests: I) -> Option<AccountId>
where I: 'a + IntoIterator<Item=(frame_support::ConsensusEngineId, &'a [u8])>
{
pallet_aura::AuraAuthorId::<Runtime>::find_author(digests).and_then(|k| {
AccountId::try_from(k.as_ref()).ok()
})
}
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = AuraAccountAdapter;
type UncleGenerations = ();
type FilterUncle = ();
type EventHandler = ();
}
- Create OnUnbalanced implementation of Author and DealWithFees
use crate::{Authorship, Balances};
use frame_support::traits::{Imbalance, OnUnbalanced};
use crate::sp_api_hidden_includes_construct_runtime::hidden_include::traits::Currency;
use crate::AccountId;
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
pub struct DealWithFees;
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
if let Some(fees) = fees_then_tips.next() {
let mut split = fees.ration(80, 20);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 80% to treasury, 20% to block author (though this can be anything)
tips.ration_merge_into(80, 20, &mut split);
}
//Treasury::on_unbalanced(split.0);
Author::on_unbalanced(split.1);
}
}
}
- Call the implementation in the pallet_transaction_payment tuple OnChargeTransaction
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = CurrencyAdapter<Balances, crate::impls::DealWithFees>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
}
Also added in my blog: https://hgminerva.wordpress.com/2022/06/21/how-to-pay-the-block-author-validator-on-a-proof-of-authority-poa-consensus-in-substrate/
The above is about allowing the transaction fees to be split between validators. If you want inflation as well, this can currently only be done if you use pallet-staking
. Inflationary rewards are minted in pallet-staking
, and can configured via the type EraPayout
. See EraPayout
.
-
I am just using Aura for the time being. I want to pay the block authors/validators of the existing PoA. Commented Jun 20, 2022 at 8:36
This can be handled with OnUnbalanced on NegativeImbalance event when a fee is charged, here is sample code
You will also need to integrate authorship pallet to pass the author (validator) information, here is a snippet for this.
-
Thanks for the response! Although FYI it is always best practice to link out and provide directly a snippet here for reference. Both for keeping people from having to jump out of the site, but more importantly because those resources may disappear latter on or change– NukeCommented Jun 20, 2022 at 2:52
-
So I need the following task for my substrate-node-template: 1. Import pallet_session 2. Import pallet_authorship 3. Implement both pallets in the /runtime/lib.rs 4. Implement OnUnbalanced event for Author struct 5. Implement OnUnbalanced event for DealtWithFees struct Commented Jun 20, 2022 at 5:09
Please correct me if I am wrong on this Mo Elshami. These are the step on how to provide reward to your PoA validators in the substrate-node-template.
- Import the pallet_session (runtime/Cargo.toml)
pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false }`
- Import the pallet_authorship (runtime/Cargo.toml)
pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authorship" }`
- Implement both pallet in the /runtime/lib.rs
parameter_types! {
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
pub const MaxAuthorities: u32 = 100_000;
}
impl pallet_session::Config for Runtime {
type Event = Event;
type ValidatorId = <Self as frame_system::Config>::AccountId;
// we don't have stash and controller, thus we don't need the convert as well.
type ValidatorIdOf = pallet_collator_selection::IdentityCollator;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = CollatorSelection;
// Essentially just Aura, but lets be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type WeightInfo = ();
}
parameter_types! {
pub const UncleGenerations: u32 = 0;
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Aura>;
type UncleGenerations = UncleGenerations;
type FilterUncle = ();
type EventHandler = (CollatorSelection,);
}
- Implement OnUnbalanced event for Author and DealtWithFees struct
use crate::{Authorship, Balances, NegativeImbalance, Treasury};
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
pub struct DealWithFees;
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
if let Some(fees) = fees_then_tips.next() {
let mut split = fees.ration(80, 20);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 80% to treasury, 20% to block author (though this can be anything)
tips.ration_merge_into(80, 20, &mut split);
}
Treasury::on_unbalanced(split.0);
Author::on_unbalanced(split.1);
}
}
}