Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5ac97f2
Setting up AlephBFT version
maciejzelaszczyk Aug 30, 2022
27e43a9
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Aug 31, 2022
62126ec
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Aug 31, 2022
459d145
Changed handling to map from session to version
maciejzelaszczyk Aug 31, 2022
ac02944
Changed logic to handle serving last set AlephBFT version
maciejzelaszczyk Sep 1, 2022
fb4b788
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 5, 2022
c707921
Changed logic to handle setting of version in future only
maciejzelaszczyk Sep 5, 2022
afa232b
Reworked storage and accessors to only store one version plus session…
maciejzelaszczyk Sep 6, 2022
3eea0df
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 7, 2022
357e2d9
Treat version change as a delimiting flag
maciejzelaszczyk Sep 7, 2022
b74359d
Loose coupling between pallet_aleph and pallet_session to access curr…
maciejzelaszczyk Sep 7, 2022
7c900a3
Fixed trait implementation for mock
maciejzelaszczyk Sep 8, 2022
4ae4f4c
Added comment to trait
maciejzelaszczyk Sep 8, 2022
71c1538
Replaced panics with Results in AlephBFT version handling
maciejzelaszczyk Sep 8, 2022
9ef7f8f
Changed logic to work with numbered versions
maciejzelaszczyk Sep 12, 2022
c781a0c
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 12, 2022
0fee02d
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 13, 2022
e0d9fb3
Changed behavior on session start and end
maciejzelaszczyk Sep 13, 2022
157d49b
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 14, 2022
7eea19c
Fixed version change update
maciejzelaszczyk Sep 15, 2022
5ff7256
Linked SessionManager in runtime
maciejzelaszczyk Sep 16, 2022
08a0dc6
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 16, 2022
f63875b
Mock impl
maciejzelaszczyk Sep 16, 2022
3f68522
Reworked SessionManage link
maciejzelaszczyk Sep 16, 2022
002a2b5
Linter
maciejzelaszczyk Sep 16, 2022
9b70cc4
Removed pallet_elections from mock
maciejzelaszczyk Sep 16, 2022
4853d8b
Removed event
maciejzelaszczyk Sep 16, 2022
706c9b1
linter
maciejzelaszczyk Sep 16, 2022
66989bf
Linter
maciejzelaszczyk Sep 16, 2022
23ae4a8
Reworked AlephBFT version history updates
maciejzelaszczyk Sep 19, 2022
f0bb79a
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 20, 2022
f23314e
Reworked storage to use value instead of map
maciejzelaszczyk Sep 22, 2022
6416805
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 22, 2022
f08cb5f
Added unit test
maciejzelaszczyk Sep 22, 2022
f11a76c
Added version change unscheduling and next session version
maciejzelaszczyk Sep 23, 2022
1ca8421
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 26, 2022
8c46f55
Removed explicit version unscheduling; added version default
maciejzelaszczyk Sep 26, 2022
b76b5d3
Extended docs for pallet aleph
maciejzelaszczyk Sep 27, 2022
8f3d600
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 27, 2022
ab33ed1
Moved default AlephBFT version to const
maciejzelaszczyk Sep 27, 2022
df25289
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Sep 30, 2022
cc89848
Renamed helper function
maciejzelaszczyk Oct 3, 2022
5a331e7
Merge branch 'A0-1323-aleph-bft-version-coordination' of github.com:C…
maciejzelaszczyk Oct 3, 2022
94519a2
Fixed test
maciejzelaszczyk Oct 3, 2022
1e9daef
Changed naming
maciejzelaszczyk Oct 3, 2022
27a1207
Bumped spec version
maciejzelaszczyk Oct 3, 2022
6599a4e
Bumped transaction version
maciejzelaszczyk Oct 4, 2022
95a7fdd
Merge branch 'main' into A0-1323-aleph-bft-version-coordination
maciejzelaszczyk Oct 19, 2022
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
3 changes: 3 additions & 0 deletions .github/scripts/run_consensus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ set -euo pipefail
NODE_COUNT=5
MIN_VALIDATOR_COUNT=4

# default minimum validator count
MIN_VALIDATOR_COUNT=4

export NODE_IMAGE=aleph-node:latest

mkdir -p docker/data/
Expand Down
18 changes: 14 additions & 4 deletions bin/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustm
pub use primitives::Balance;
use primitives::{
staking::MAX_NOMINATORS_REWARDED_PER_VALIDATOR, wrap_methods, ApiError as AlephApiError,
AuthorityId as AlephId, SessionAuthorityData, ADDRESSES_ENCODING,
AuthorityId as AlephId, SessionAuthorityData, Version as FinalityVersion, ADDRESSES_ENCODING,
DEFAULT_KICK_OUT_REASON_LENGTH, DEFAULT_SESSIONS_PER_ERA, DEFAULT_SESSION_PERIOD,
MILLISECS_PER_BLOCK, TOKEN,
};
Expand Down Expand Up @@ -108,10 +108,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("aleph-node"),
impl_name: create_runtime_str!("aleph-node"),
authoring_version: 1,
spec_version: 35,
spec_version: 36,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 10,
transaction_version: 11,
state_version: 0,
};

Expand Down Expand Up @@ -313,6 +313,8 @@ impl pallet_sudo::Config for Runtime {
impl pallet_aleph::Config for Runtime {
type AuthorityId = AlephId;
type Event = Event;
type SessionInfoProvider = Session;
type SessionManager = Elections;
}

impl_opaque_keys! {
Expand Down Expand Up @@ -350,7 +352,7 @@ impl pallet_session::Config for Runtime {
type ValidatorIdOf = pallet_staking::StashOf<Self>;
type ShouldEndSession = pallet_session::PeriodicSessions<SessionPeriod, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<SessionPeriod, Offset>;
type SessionManager = Elections;
type SessionManager = Aleph;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type WeightInfo = pallet_session::weights::SubstrateWeight<Runtime>;
Expand Down Expand Up @@ -898,6 +900,14 @@ impl_runtime_apis! {
Aleph::queued_emergency_finalizer(),
))
}

fn finality_version() -> FinalityVersion {
Aleph::finality_version()
}

fn next_session_finality_version() -> FinalityVersion {
Aleph::next_session_finality_version()
}
}

impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash> for Runtime {
Expand Down
52 changes: 52 additions & 0 deletions pallets/aleph/src/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use primitives::SessionIndex;
use sp_std::vec::Vec;

use crate::{Config, Event, FinalityScheduledVersionChange, FinalityVersion, Pallet};

impl<T> pallet_session::SessionManager<T::AccountId> for Pallet<T>
where
T: Config,
{
fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
<T as Config>::SessionManager::new_session(new_index)
}

fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
<T as Config>::SessionManager::new_session_genesis(new_index)
}

fn end_session(end_index: SessionIndex) {
<T as Config>::SessionManager::end_session(end_index);
}

fn start_session(start_index: SessionIndex) {
<T as Config>::SessionManager::start_session(start_index);
Self::update_version_change_history();
}
}

impl<T> Pallet<T>
where
T: Config,
{
// Check if a schedule version change has moved into the past. Update history, even if there is
// no change. Resets the scheduled version.
fn update_version_change_history() {
let current_session = Self::current_session();

if let Some(scheduled_version_change) = <FinalityScheduledVersionChange<T>>::get() {
let scheduled_session = scheduled_version_change.session;
let scheduled_version = scheduled_version_change.version_incoming;

// Record the scheduled version as the current version as it moves into the past.
if scheduled_session == current_session {
<FinalityVersion<T>>::put(scheduled_version);

// Reset the scheduled version.
<FinalityScheduledVersionChange<T>>::kill();

Self::deposit_event(Event::FinalityVersionChange(scheduled_version_change));
}
}
}
}
112 changes: 111 additions & 1 deletion pallets/aleph/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
//! This pallet is a runtime companion of Aleph finality gadget.
//! This pallet is the runtime companion of the Aleph finality gadget.
//!
//! Currently, it only provides support for changing sessions but in the future
//! it will allow reporting equivocation in AlephBFT.
//!
//! This pallet relies on an extension of the `AlephSessionApi` Runtime API to handle the finality
//! version. The scheduled version change is persisted as `FinalityScheduledVersionChange`. This
//! value stores the information about a scheduled finality version change, where `version_incoming`
//! is the version to be set and `session` is the session on which the new version will be set.
//! A `pallet_session::Session_Manager` checks whether a scheduled version change has moved into
//! the past and, if so, records it as the current version represented as `FinalityVersion`,
//! and clears `FinalityScheduledVersionChange`.
//! It is always possible to reschedule a version change. In order to cancel a scheduled version
//! change rather than reschedule it, a new version change should be scheduled with
//! `version_incoming` set to the current value of `FinalityVersion`.

#![cfg_attr(not(feature = "std"), no_std)]

Expand All @@ -10,40 +21,51 @@ mod mock;
#[cfg(test)]
mod tests;

mod impls;
mod migrations;
mod traits;

use frame_support::{
log,
sp_runtime::BoundToRuntimeAppPublic,
traits::{OneSessionHandler, StorageVersion},
};
pub use pallet::*;
use primitives::{SessionIndex, Version, VersionChange};
use sp_std::prelude::*;

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);

const DEFAULT_FINALITY_VERSION: Version = 0;

#[frame_support::pallet]
pub mod pallet {
use frame_support::{pallet_prelude::*, sp_runtime::RuntimeAppPublic};
use frame_system::{
ensure_root,
pallet_prelude::{BlockNumberFor, OriginFor},
};
use pallet_session::SessionManager;
use pallets_support::StorageMigration;

use super::*;
use crate::traits::SessionInfoProvider;

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

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
ChangeEmergencyFinalizer(T::AuthorityId),
ScheduleFinalityVersionChange(VersionChange),
FinalityVersionChange(VersionChange),
}

#[pallet::pallet]
Expand Down Expand Up @@ -77,6 +99,12 @@ pub mod pallet {
}
}

/// Default finality version. Relevant for sessions before the first version change occurs.
#[pallet::type_value]
pub(crate) fn DefaultFinalityVersion<T: Config>() -> Version {
DEFAULT_FINALITY_VERSION
}

#[pallet::storage]
#[pallet::getter(fn authorities)]
pub(super) type Authorities<T: Config> = StorageValue<_, Vec<T::AuthorityId>, ValueQuery>;
Expand All @@ -93,6 +121,18 @@ pub mod pallet {
#[pallet::storage]
type NextEmergencyFinalizer<T: Config> = StorageValue<_, T::AuthorityId, OptionQuery>;

/// Current finality version.
#[pallet::storage]
#[pallet::getter(fn finality_version)]
pub(super) type FinalityVersion<T: Config> =
StorageValue<_, Version, ValueQuery, DefaultFinalityVersion<T>>;

/// Scheduled finality version change.
#[pallet::storage]
#[pallet::getter(fn finality_version_change)]
pub(super) type FinalityScheduledVersionChange<T: Config> =
StorageValue<_, VersionChange, OptionQuery>;

impl<T: Config> Pallet<T> {
pub(crate) fn initialize_authorities(authorities: &[T::AuthorityId]) {
if !authorities.is_empty() {
Expand Down Expand Up @@ -121,6 +161,49 @@ pub mod pallet {
pub(crate) fn set_next_emergency_finalizer(emergency_finalizer: T::AuthorityId) {
<NextEmergencyFinalizer<T>>::put(emergency_finalizer);
}

pub(crate) fn current_session() -> u32 {
T::SessionInfoProvider::current_session()
}

// If a scheduled future version change is rescheduled to a different session,
// it is possible to reschedule it with the same version as initially.
// To cancel a future version change, reschedule it with the current version.
// If a scheduled version change has moved into the past, `SessionManager` records it
// as the current version.
pub(crate) fn do_schedule_finality_version_change(
version_change: VersionChange,
) -> Result<(), &'static str> {
let current_session = Self::current_session();

let session_to_schedule = version_change.session;

if session_to_schedule < current_session {
return Err("Cannot schedule finality version changes for sessions in the past!");
} else if session_to_schedule < current_session + 2 {
return Err(
"Tried to schedule an finality version change less than 2 sessions in advance!",
);
}

// Update the scheduled version change with the supplied version change.
<FinalityScheduledVersionChange<T>>::put(version_change);

Ok(())
}

pub fn next_session_finality_version() -> Version {
let next_session = Self::current_session() + 1;
let scheduled_version_change = Self::finality_version_change();

if let Some(version_change) = scheduled_version_change {
if next_session == version_change.session {
return version_change.version_incoming;
}
}

Self::finality_version()
}
}

#[pallet::call]
Expand All @@ -137,6 +220,33 @@ pub mod pallet {
Self::deposit_event(Event::ChangeEmergencyFinalizer(emergency_finalizer));
Ok(())
}

/// Schedules a finality version change for a future session. If such a scheduled future
/// version is already set, it is replaced with the provided one.
/// Any rescheduling of a future version change needs to occur at least 2 sessions in
/// advance of the provided session of the version change.
/// In order to cancel a scheduled version change, a new version change should be scheduled
/// with the same version as the current one.
#[pallet::weight((T::BlockWeights::get().max_block, DispatchClass::Operational))]
pub fn schedule_finality_version_change(
origin: OriginFor<T>,
version_incoming: Version,
session: SessionIndex,
) -> DispatchResult {
ensure_root(origin)?;

let version_change = VersionChange {
version_incoming,
session,
};

if let Err(e) = Self::do_schedule_finality_version_change(version_change.clone()) {
return Err(DispatchError::Other(e));
}

Self::deposit_event(Event::ScheduleFinalityVersionChange(version_change));
Ok(())
}
}

impl<T: Config> BoundToRuntimeAppPublic for Pallet<T> {
Expand Down
4 changes: 3 additions & 1 deletion pallets/aleph/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl pallet_session::Config for Test {
type ValidatorIdOf = ConvertInto;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = ();
type SessionManager = Aleph;
type SessionHandler = <TestSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = TestSessionKeys;
type WeightInfo = ();
Expand Down Expand Up @@ -133,6 +133,8 @@ impl pallet_timestamp::Config for Test {
impl Config for Test {
type AuthorityId = AuthorityId;
type Event = Event;
type SessionInfoProvider = Session;
type SessionManager = ();
}

pub fn to_authority(id: &u64) -> AuthorityId {
Expand Down
38 changes: 38 additions & 0 deletions pallets/aleph/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![cfg(test)]

use frame_support::{storage_alias, traits::OneSessionHandler};
use primitives::VersionChange;

use crate::mock::*;

Expand Down Expand Up @@ -130,3 +131,40 @@ fn test_emergency_signer() {
assert_eq!(Aleph::queued_emergency_finalizer(), Some(to_authority(&37)));
})
}

#[test]
fn test_finality_version_scheduling() {
new_test_ext(&[(1u64, 1u64), (2u64, 2u64)]).execute_with(|| {
initialize_session();

run_session(1);

let version_to_schedule = VersionChange {
version_incoming: 1,
session: 4,
};

let scheduling_result =
Aleph::do_schedule_finality_version_change(version_to_schedule.clone());
assert_eq!(scheduling_result, Ok(()));

let scheduled_version_change = Aleph::finality_version_change();
assert_eq!(scheduled_version_change, Some(version_to_schedule.clone()));

run_session(4);

let current_version = Aleph::finality_version();
assert_eq!(current_version, version_to_schedule.version_incoming);

let scheduled_version_change = Aleph::finality_version_change();
assert_eq!(scheduled_version_change, None);

let version_to_schedule = VersionChange {
version_incoming: 1,
session: 5,
};

let scheduling_result = Aleph::do_schedule_finality_version_change(version_to_schedule);
assert!(scheduling_result.is_err());
})
}
15 changes: 15 additions & 0 deletions pallets/aleph/src/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use primitives::SessionIndex;

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

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