Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aleph-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "aleph_client"
# TODO bump major version when API stablize
version = "2.8.0"
version = "2.9.0"
edition = "2021"
license = "Apache 2.0"

Expand Down
27 changes: 24 additions & 3 deletions aleph-client/src/aleph_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6338,6 +6338,27 @@ pub mod api {
],
)
}
pub fn next_authorities(
&self,
) -> ::subxt::storage::address::StaticStorageAddress<
::subxt::metadata::DecodeStaticType<
::std::vec::Vec<runtime_types::primitives::app::Public>,
>,
::subxt::storage::address::Yes,
::subxt::storage::address::Yes,
(),
> {
::subxt::storage::address::StaticStorageAddress::new(
"Aleph",
"NextAuthorities",
vec![],
[
241u8, 145u8, 255u8, 235u8, 191u8, 220u8, 57u8, 89u8, 8u8, 134u8, 72u8,
193u8, 247u8, 37u8, 54u8, 201u8, 136u8, 32u8, 11u8, 199u8, 134u8,
207u8, 154u8, 107u8, 71u8, 121u8, 245u8, 153u8, 9u8, 33u8, 70u8, 3u8,
],
)
}
pub fn emergency_finalizer(
&self,
) -> ::subxt::storage::address::StaticStorageAddress<
Expand Down Expand Up @@ -19532,9 +19553,9 @@ pub mod api {
let runtime_metadata_hash = client.metadata().metadata_hash(&PALLETS);
if runtime_metadata_hash
!= [
10u8, 121u8, 157u8, 11u8, 147u8, 107u8, 235u8, 73u8, 90u8, 254u8, 82u8, 183u8,
112u8, 64u8, 213u8, 99u8, 23u8, 17u8, 10u8, 91u8, 124u8, 231u8, 209u8, 172u8, 59u8,
160u8, 15u8, 142u8, 149u8, 200u8, 95u8, 164u8,
51u8, 153u8, 218u8, 203u8, 158u8, 62u8, 141u8, 96u8, 177u8, 177u8, 12u8, 204u8,
220u8, 53u8, 42u8, 155u8, 22u8, 96u8, 238u8, 212u8, 98u8, 225u8, 39u8, 241u8, 52u8,
28u8, 166u8, 99u8, 14u8, 192u8, 65u8, 67u8,
]
{
Err(::subxt::error::MetadataError::IncompatibleMetadata)
Expand Down
28 changes: 18 additions & 10 deletions bin/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use sp_runtime::{
OpaqueKeys, Verify,
},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedU128, MultiSignature, RuntimeAppPublic,
ApplyExtrinsicResult, FixedU128, MultiSignature,
};
pub use sp_runtime::{FixedPointNumber, Perbill, Permill};
use sp_staking::EraIndex;
Expand Down Expand Up @@ -104,7 +104,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("aleph-node"),
impl_name: create_runtime_str!("aleph-node"),
authoring_version: 1,
spec_version: 45,
spec_version: 46,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 14,
Expand Down Expand Up @@ -316,6 +316,7 @@ impl pallet_aleph::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type SessionInfoProvider = Session;
type SessionManager = Elections;
type NextSessionAuthorityProvider = Session;
}

impl_opaque_keys! {
Expand Down Expand Up @@ -372,13 +373,17 @@ parameter_types! {
}

use sp_runtime::traits::Convert;

pub struct BalanceToU256;

impl Convert<Balance, sp_core::U256> for BalanceToU256 {
fn convert(balance: Balance) -> sp_core::U256 {
sp_core::U256::from(balance)
}
}

pub struct U256ToBalance;

impl Convert<sp_core::U256, Balance> for U256ToBalance {
fn convert(n: sp_core::U256) -> Balance {
n.try_into().unwrap_or(Balance::max_value())
Expand Down Expand Up @@ -423,6 +428,7 @@ impl pallet_staking::EraPayout<Balance> for UniformEraPayout {
type SubstrateStakingWeights = pallet_staking::weights::SubstrateWeight<Runtime>;

pub struct PayoutStakersDecreasedWeightInfo;

impl pallet_staking::WeightInfo for PayoutStakersDecreasedWeightInfo {
// To make possible to change nominators per validator we need to decrease weight for payout_stakers
fn payout_stakers_alive_staked(n: u32) -> Weight {
Expand Down Expand Up @@ -493,6 +499,7 @@ impl pallet_staking::WeightInfo for PayoutStakersDecreasedWeightInfo {
}

pub struct StakingBenchmarkingConfig;

impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig {
type MaxValidators = ConstU32<1000>;
type MaxNominators = ConstU32<1000>;
Expand Down Expand Up @@ -609,6 +616,7 @@ parameter_types! {
}

pub struct TreasuryGovernance;

impl SortedMembers<AccountId> for TreasuryGovernance {
fn sorted_members() -> Vec<AccountId> {
pallet_sudo::Pallet::<Runtime>::key().into_iter().collect()
Expand Down Expand Up @@ -884,21 +892,21 @@ impl_runtime_apis! {
}

fn next_session_authorities() -> Result<Vec<AlephId>, AlephApiError> {
Session::queued_keys()
.iter()
.map(|(_, key)| key.get(AlephId::ID).ok_or(AlephApiError::DecodeKey))
.collect::<Result<Vec<AlephId>, AlephApiError>>()
let next_authorities = Aleph::next_authorities();
if next_authorities.is_empty() {
return Err(AlephApiError::MissingAuthoritiesForNextSession)
}

Ok(next_authorities)
}

fn authority_data() -> SessionAuthorityData {
SessionAuthorityData::new(Aleph::authorities(), Aleph::emergency_finalizer())
}

fn next_session_authority_data() -> Result<SessionAuthorityData, AlephApiError> {
Ok(SessionAuthorityData::new(Session::queued_keys()
.iter()
.map(|(_, key)| key.get(AlephId::ID).ok_or(AlephApiError::DecodeKey))
.collect::<Result<Vec<AlephId>, AlephApiError>>()?,
Ok(SessionAuthorityData::new(
Self::next_session_authorities()?,
Aleph::queued_emergency_finalizer(),
))
}
Expand Down
51 changes: 38 additions & 13 deletions pallets/aleph/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ pub mod pallet {
use pallets_support::StorageMigration;

use super::*;
use crate::traits::SessionInfoProvider;
use crate::traits::{NextSessionAuthorityProvider, SessionInfoProvider};

#[pallet::config]
pub trait Config: frame_system::Config {
type AuthorityId: Member + Parameter + RuntimeAppPublic + MaybeSerializeDeserialize;
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type SessionInfoProvider: SessionInfoProvider<Self>;
type SessionInfoProvider: SessionInfoProvider;
type SessionManager: SessionManager<<Self as frame_system::Config>::AccountId>;
type NextSessionAuthorityProvider: NextSessionAuthorityProvider<Self>;
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
#[pallet::generate_deposit(pub (super) fn deposit_event)]
pub enum Event<T: Config> {
ChangeEmergencyFinalizer(T::AuthorityId),
ScheduleFinalityVersionChange(VersionChange),
Expand Down Expand Up @@ -105,10 +106,21 @@ pub mod pallet {
DEFAULT_FINALITY_VERSION
}

/// Default finality version. Relevant for sessions before the first version change occurs.
#[pallet::type_value]
pub(crate) fn DefaultNextAuthorities<T: Config>() -> Vec<T::AuthorityId> {
T::NextSessionAuthorityProvider::next_authorities()
}

#[pallet::storage]
#[pallet::getter(fn authorities)]
pub(super) type Authorities<T: Config> = StorageValue<_, Vec<T::AuthorityId>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn next_authorities)]
pub(super) type NextAuthorities<T: Config> =
StorageValue<_, Vec<T::AuthorityId>, ValueQuery, DefaultNextAuthorities<T>>;

#[pallet::storage]
#[pallet::getter(fn emergency_finalizer)]
pub(super) type EmergencyFinalizer<T: Config> = StorageValue<_, T::AuthorityId, OptionQuery>;
Expand All @@ -134,18 +146,29 @@ pub mod pallet {
StorageValue<_, VersionChange, OptionQuery>;

impl<T: Config> Pallet<T> {
pub(crate) fn initialize_authorities(authorities: &[T::AuthorityId]) {
pub(crate) fn initialize_authorities(
authorities: &[T::AuthorityId],
next_authorities: &[T::AuthorityId],
) {
if !authorities.is_empty() {
assert!(
<Authorities<T>>::get().is_empty(),
"Authorities are already initialized!"
);
<Authorities<T>>::put(authorities);
if !<Authorities<T>>::get().is_empty() {
log::error!(target: "pallet_aleph","Authorities are already initialized!");
} else {
<Authorities<T>>::put(authorities);
}
}
if !next_authorities.is_empty() {
// Storage NextAuthorities has default value so should never be empty.
<NextAuthorities<T>>::put(next_authorities);
}
}

pub(crate) fn update_authorities(authorities: &[T::AuthorityId]) {
pub(crate) fn update_authorities(
authorities: &[T::AuthorityId],
next_authorities: &[T::AuthorityId],
) {
<Authorities<T>>::put(authorities);
<NextAuthorities<T>>::put(next_authorities);
}

pub(crate) fn update_emergency_finalizer() {
Expand Down Expand Up @@ -262,18 +285,20 @@ pub mod pallet {
T::AccountId: 'a,
{
let (_, authorities): (Vec<_>, Vec<_>) = validators.unzip();
Self::initialize_authorities(authorities.as_slice());
// it is guaranteed that the first validator set will also be used in the next session
Self::initialize_authorities(authorities.as_slice(), authorities.as_slice());
}

fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I)
fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued_validators: I)
where
I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)>,
T::AccountId: 'a,
{
Self::update_emergency_finalizer();
if changed {
let (_, authorities): (Vec<_>, Vec<_>) = validators.unzip();
Self::update_authorities(authorities.as_slice());
let (_, next_authorities): (Vec<_>, Vec<_>) = queued_validators.unzip();
Self::update_authorities(authorities.as_slice(), next_authorities.as_slice());
}
}

Expand Down
21 changes: 16 additions & 5 deletions pallets/aleph/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,29 @@ fn test_update_authorities() {
initialize_session();
run_session(1);

Aleph::update_authorities(to_authorities(&[2, 3, 4]).as_slice());
let authorities = to_authorities(&[2, 3, 4]);

Aleph::update_authorities(authorities.as_slice(), authorities.as_slice());

assert_eq!(Aleph::authorities(), to_authorities(&[2, 3, 4]));
assert_eq!(Aleph::next_authorities(), to_authorities(&[2, 3, 4]));
});
}

#[test]
fn test_initialize_authorities() {
new_test_ext(&[(1u64, 1u64), (2u64, 2u64)]).execute_with(|| {
assert_eq!(Aleph::authorities(), to_authorities(&[1, 2]));
assert_eq!(Aleph::next_authorities(), to_authorities(&[1, 2]));
});
}

#[test]
#[should_panic]
fn fails_to_initialize_again_authorities() {
new_test_ext(&[(1u64, 1u64), (2u64, 2u64)]).execute_with(|| {
Aleph::initialize_authorities(&to_authorities(&[1, 2, 3]));
let authorities = to_authorities(&[1, 2, 3]);
Aleph::initialize_authorities(&authorities, &authorities);
});
}

Expand All @@ -81,15 +86,20 @@ fn test_current_authorities() {

run_session(1);

Aleph::update_authorities(to_authorities(&[2, 3, 4]).as_slice());
let authorities = to_authorities(&[2, 3, 4]);

Aleph::update_authorities(&authorities, &authorities);

assert_eq!(Aleph::authorities(), to_authorities(&[2, 3, 4]));
assert_eq!(Aleph::next_authorities(), to_authorities(&[2, 3, 4]));

run_session(2);

Aleph::update_authorities(to_authorities(&[1, 2, 3]).as_slice());
let authorities = to_authorities(&[1, 2, 3]);
Aleph::update_authorities(&authorities, &authorities);

assert_eq!(Aleph::authorities(), to_authorities(&[1, 2, 3]));
assert_eq!(Aleph::next_authorities(), to_authorities(&[1, 2, 3]));
})
}

Expand All @@ -100,9 +110,10 @@ fn test_session_rotation() {
run_session(1);

let new_validators = new_session_validators(&[3u64, 4u64]);
let queued_validators = new_session_validators(&[]);
let queued_validators = new_session_validators(&[5, 6]);
Aleph::on_new_session(true, new_validators, queued_validators);
assert_eq!(Aleph::authorities(), to_authorities(&[3, 4]));
assert_eq!(Aleph::next_authorities(), to_authorities(&[5, 6]));
})
}

Expand Down
36 changes: 33 additions & 3 deletions pallets/aleph/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
use primitives::SessionIndex;
use frame_support::{
log,
sp_runtime::{traits::OpaqueKeys, RuntimeAppPublic},
};
use primitives::{AuthorityId, SessionIndex};
use sp_std::prelude::*;

use crate::Config;

/// Information provider from `pallet_session`. Loose pallet coupling via traits.
pub trait SessionInfoProvider<T: frame_system::Config> {
pub trait SessionInfoProvider {
fn current_session() -> SessionIndex;
}

impl<T> SessionInfoProvider<T> for pallet_session::Pallet<T>
/// Authorities provider, used only as default value in case of missing this information in our pallet. This can
/// happen for the session after runtime upgraded.
pub trait NextSessionAuthorityProvider<T: Config> {
fn next_authorities() -> Vec<T::AuthorityId>;
}

impl<T> SessionInfoProvider for pallet_session::Pallet<T>
where
T: pallet_session::Config,
{
fn current_session() -> SessionIndex {
pallet_session::CurrentIndex::<T>::get()
}
}

impl<T> NextSessionAuthorityProvider<T> for pallet_session::Pallet<T>
where
T: Config + pallet_session::Config,
{
fn next_authorities() -> Vec<T::AuthorityId> {
let next: Option<Vec<_>> = pallet_session::Pallet::<T>::queued_keys()
.iter()
.map(|(_, key)| key.get(AuthorityId::ID))
.collect();

next.unwrap_or_else(|| {
log::error!(target: "pallet_aleph", "Missing next session keys");
vec![]
})
}
}
2 changes: 1 addition & 1 deletion primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<AccountId> Default for EraValidators<AccountId> {

#[derive(Encode, Decode, PartialEq, Eq, Debug)]
pub enum ApiError {
DecodeKey,
MissingAuthoritiesForNextSession,
}

/// All the data needed to verify block finalization justifications.
Expand Down