node-template起始共识是Aura,就是Round Robin轮流出块的简单机制,现在改成Babe就是基于插槽VRF的共识
1. 依赖修改
runtime的Cargo.toml搜索有两处aura
pallet-aura = { version = "3.0.0", default-features = false }
sp-consensus-aura = { version = "0.9.0", default-features = false }
修改成:
pallet-babe = { version = "3.0.0", default-features = false }
sp-consensus-babe = { version = "0.9.0", default-features = false }
还有std中的
还有node的Cargo.toml也有两处
sc-consensus-aura = "0.9.0"
sp-consensus-aura = "0.9.0"
2. 修改runtime的lib.rs, 搜索Aura
把SessionKey修改:
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
pub grandpa: Grandpa,
}
}
改成:
impl_opaque_keys! {
pub struct SessionKeys {
pub babe: Babe,
pub grandpa: Grandpa,
}
}
把aura的定义改成:
parameter_types! {
pub const EpochDuration: u64 = EPOCH_DURATION_IN_BLOCKS as u64;
pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
pub const ReportLongevity: u64 = 0; // by Skyh
// BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); // Kusama
}
impl pallet_babe::Config for Runtime {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
type KeyOwnerProofSystem = (); // Historical;
type KeyOwnerProof =
>::Proof;
type KeyOwnerIdentification =
>::IdentificationTuple;
type HandleEquivocation = (); //pallet_babe::EquivocationHandler; // () Offences
type WeightInfo = ();
}
修改construct_runtime的Aura:
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
Sudo: pallet_sudo::{Module, Call, Config, Storage, Event},
System: frame_system::{Module, Call, Config, Storage, Event},
Balances: pallet_balances::{Module, Call, Storage, Config, Event},
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
TransactionPayment: pallet_transaction_payment::{Module, Storage},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
Babe: pallet_babe::{Module, Call, Storage, Config, Inherent, ValidateUnsigned},
Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event, ValidateUnsigned},
// Include the custom logic from the template pallet in the runtime.
TemplateModule: template::{Module, Call, Storage, Event},
}
);
修改impl_runtime_apis中的AuraApi
impl sp_consensus_babe::BabeApi for Runtime {
fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration {
sp_consensus_babe::BabeGenesisConfiguration {
slot_duration: Babe::slot_duration(),
epoch_length: EpochDuration::get(),
c: PRIMARY_PROBABILITY,
genesis_authorities: Babe::authorities(),
randomness: Babe::randomness(),
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
}
}
fn current_epoch_start() -> sp_consensus_babe::Slot {
Babe::current_epoch_start()
}
fn current_epoch() -> sp_consensus_babe::Epoch {
Babe::current_epoch()
}
fn next_epoch() -> sp_consensus_babe::Epoch {
Babe::next_epoch()
}
fn generate_key_ownership_proof(
_slot: sp_consensus_babe::Slot,
authority_id: sp_consensus_babe::AuthorityId,
) -> Option {
use codec::Encode;
Historical::prove((sp_consensus_babe::KEY_TYPE, authority_id))
.map(|p| p.encode())
.map(sp_consensus_babe::OpaqueKeyOwnershipProof::new)
}
fn submit_report_equivocation_unsigned_extrinsic(
equivocation_proof: sp_consensus_babe::EquivocationProof<::Header>,
key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof,
) -> Option<()> {
let key_owner_proof = key_owner_proof.decode()?;
Babe::submit_unsigned_equivocation_report(
equivocation_proof,
key_owner_proof,
)
}
}
坑:在这里,高度抽象化必须对应看人家项目使用Historical,所以必须在runtime中加入:
# historical的特性
pallet-session = { version = "3.0.0", default-features = false, features = ["historical"] }
impl pallet_session::historical::Config for Runtime {
type FullIdentification = pallet_staking::Exposure;
type FullIdentificationOf = pallet_staking::ExposureOf;
}
Historical: session_historical::{Module},
坑2:也要加入staking, 这算耦合么,暂时没有好的解决方法
pallet-staking = { version = "3.0.0", default-features = false }
也在babe和grandpa加入KeyOwnerProofSystem为Historical
编译报错要实现super的session的config
3. 被逼加入session和staking
具体代码
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
}
impl pallet_session::Config for Runtime {
type Event = Event;
type ValidatorId = ::AccountId;
type ValidatorIdOf = pallet_staking::StashOf;
type Keys = SessionKeys;
type ShouldEndSession = Babe;
type NextSessionRotation = Babe;
type SessionManager = pallet_session::historical::NoteHistoricalRoot;
type SessionHandler = ::KeyTypeIdProviders;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
}
impl pallet_session::historical::Config for Runtime {
type FullIdentification = pallet_staking::Exposure;
type FullIdentificationOf = pallet_staking::ExposureOf;
}
又必须加入staking
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_025_000,
max_inflation: 0_100_000,
ideal_stake: 0_500_000,
falloff: 0_050_000,
max_piece_count: 40,
test_precision: 0_005_000,
);
}
parameter_types! {
pub const SessionsPerEra: sp_staking::SessionIndex = 3; // 3 hours
pub const BondingDuration: pallet_staking::EraIndex = 4; // 12 hours
pub const SlashDeferDuration: pallet_staking::EraIndex = 2; // 6 hours
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4;
pub const MaxNominatorRewardedPerValidator: u32 = 64;
pub const MaxIterations: u32 = 5;
// 0.05%. The higher the value, the more strict solution acceptance becomes.
pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000);
pub StakingUnsignedPriority: TransactionPriority =
Perbill::from_percent(90) * TransactionPriority::max_value();
}
parameter_types! {
pub OffchainSolutionWeightLimit: Weight = BlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic
.expect("Normal extrinsics have weight limit configured by default; qed")
.saturating_sub(BlockExecutionWeight::get());
}
pub type CurrencyToVote = frame_support::traits::U128CurrencyToVote;
// TODO: Kusama
// type SlashCancelOrigin = EnsureOneOf<
// AccountId,
// EnsureRoot,
// pallet_collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>
// >;
impl pallet_staking::Config for Runtime {
type Call = Call;
type Event = Event;
type UnixTime = Timestamp;
type Currency = Balances;
type CurrencyToVote = CurrencyToVote;
type RewardRemainder = (); // TODO: Treasury
type Slash = (); // TODO: Treasury
type Reward = (); // rewards are minted from the voi
type SessionInterface = Self;
type NextNewSession = Session;
type SessionsPerEra = SessionsPerEra;
type BondingDuration = BondingDuration;
type SlashDeferDuration = SlashDeferDuration;
/// A super-majority of the council can cancel the slash.
type SlashCancelOrigin = EnsureRoot; // TODO: SlashCancelOrigin
type RewardCurve = RewardCurve;
type ElectionLookahead = ElectionLookahead;
type MinSolutionScoreBump = MinSolutionScoreBump;
type MaxIterations = MaxIterations;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type UnsignedPriority = StakingUnsignedPriority; // Kusama
type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit;
type WeightInfo = ();
}
坑3:staking需要实现SendTransactionTypes
impl frame_system::offchain::SendTransactionTypes for Runtime
where
Call: From,
{
type OverarchingCall = Call;
type Extrinsic = UncheckedExtrinsic;
}
4. 修改chain_spec.rs和service.rs
chain_spec首先先引入 BabeId
use sp_consensus_babe::AuthorityId as BabeId;
// 加session_key
fn session_keys(
babe: BabeId,
grandpa: GrandpaId,
) -> SessionKeys {
SessionKeys { babe, grandpa }
}
修改authority_keys_from_seed的AuraId
pub fn authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, BabeId, GrandpaId) {
(
get_account_id_from_seed::(&format!("{}//stash", seed)),
get_account_id_from_seed::(seed),
get_from_seed::(seed),
get_from_seed::(seed),
)
}
再在testnet_genesis中修改aura:
pallet_babe: Some(Default::default()),
pallet_grandpa: Some(Default::default()),
pallet_session: Some(SessionConfig {
keys: initial_authorities.iter().map(|x| {
(x.0.clone(),
x.0.clone(),
session_keys(
x.2.clone(), x.3.clone()
))
}).collect::>(),
}),
pallet_staking: Some(StakingConfig {
validator_count: initial_authorities.len() as u32 * 2,
minimum_validator_count: initial_authorities.len() as u32,
stakers: initial_authorities
.iter()
.map(|x| (x.0.clone(), x.1.clone(), INITIAL_STAKING, StakerStatus::Validator))
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
}),
写在最后,这次修改在这里:
https://github.com/skyh24/node-template3/commit/513d4bad382baf1f65d90608143d1bc491e9de74