diff --git a/.github/workflows/e2e-tests-main-devnet.yml b/.github/workflows/e2e-tests-main-devnet.yml index f8bed73253..d7dadc2218 100644 --- a/.github/workflows/e2e-tests-main-devnet.yml +++ b/.github/workflows/e2e-tests-main-devnet.yml @@ -466,23 +466,23 @@ jobs: follow-up-finalization-check: true timeout-minutes: 10 -# run-e2e-authorities-are-staking: -# needs: [build-test-docker, build-test-client] -# name: Run authorities are staking test -# runs-on: ubuntu-20.04 -# steps: -# - name: Checkout source code -# uses: actions/checkout@v2 -# -# - name: Run e2e test -# uses: ./.github/actions/run-e2e-test -# with: -# test-case: authorities_are_staking -# node-count: 6 -# reserved-seats: 3 -# non-reserved-seats: 3 -# follow-up-finalization-check: false -# timeout-minutes: 15 + run-e2e-authorities-are-staking: + needs: [build-test-docker, build-test-client] + name: Run authorities are staking test + runs-on: ubuntu-20.04 + steps: + - name: Checkout source code + uses: actions/checkout@v2 + + - name: Run e2e test + uses: ./.github/actions/run-e2e-test + with: + test-case: authorities_are_staking + node-count: 6 + reserved-seats: 3 + non-reserved-seats: 3 + follow-up-finalization-check: true + timeout-minutes: 15 run-e2e-ban-automatic: needs: [build-test-docker, build-test-client] @@ -570,7 +570,7 @@ jobs: - name: Run e2e test uses: ./.github/actions/run-e2e-test with: - test-case: version_upgrade::schedule_version_change + test-case: finality_version::schedule_version_change env: UPGRADE_VERSION: 1 UPGRADE_SESSION: 3 @@ -683,6 +683,21 @@ jobs: # run: | # ./scripts/catchup_version_upgrade_test.sh + run-e2e-finality-version-change: + needs: [build-test-docker, build-test-client] + name: Run finality version change test + runs-on: ubuntu-20.04 + steps: + - name: Checkout source code + uses: actions/checkout@v2 + + - name: Run e2e test + uses: ./.github/actions/run-e2e-test + with: + test-case: finality_version::finality_version_change + follow-up-finalization-check: true + timeout-minutes: 10 + check-e2e-test-suite-completion: needs: [ run-e2e-finalization-test, @@ -702,7 +717,7 @@ jobs: run-e2e-rewards-stake-change, run-e2e-rewards-change-stake-force-new-era, run-e2e-rewards-points-basic, -# run-e2e-authorities-are-staking, + run-e2e-authorities-are-staking, run-e2e-ban-automatic, run-e2e-ban-manual, run-e2e-ban-counter-clearing, @@ -712,6 +727,7 @@ jobs: run-e2e-adder-contract-test, # run-e2e-failing-version-upgrade, # run-e2e-version-upgrade-catchup, + run-e2e-finality-version-change, ] name: Check e2e test suite completion runs-on: ubuntu-20.04 diff --git a/.github/workflows/nightly-pipeline.yaml b/.github/workflows/nightly-pipeline.yaml index 5933a1c8c9..3d4c4ee2ba 100644 --- a/.github/workflows/nightly-pipeline.yaml +++ b/.github/workflows/nightly-pipeline.yaml @@ -158,22 +158,6 @@ jobs: if-no-files-found: error retention-days: 7 - run-e2e-authorities-are-staking: - needs: [build-test-docker, build-test-client] - name: Run authorities are staking test - runs-on: ubuntu-20.04 - steps: - - name: Checkout source code - uses: actions/checkout@v2 - - - name: Run e2e test - uses: ./.github/actions/run-e2e-test - with: - test-case: authorities_are_staking - node-count: 6 - follow-up-finalization-check: true - timeout-minutes: 60 - run-e2e-high-out-latency: needs: [build-synthetic-network-docker, build-test-client] name: Run high out-latency test @@ -210,7 +194,6 @@ jobs: check-e2e-test-suite-completion: needs: [ - run-e2e-authorities-are-staking, run-e2e-high-out-latency, run-e2e-no-quorum-without-high-out-latency, ] diff --git a/Cargo.lock b/Cargo.lock index 610adf393d..82b3e6bccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -290,7 +290,7 @@ dependencies = [ [[package]] name = "aleph-runtime" -version = "0.9.0" +version = "0.9.1" dependencies = [ "frame-executive", "frame-support", @@ -1886,7 +1886,7 @@ dependencies = [ [[package]] name = "finality-aleph" -version = "0.6.0" +version = "0.6.1" dependencies = [ "aggregator 0.2.1", "aggregator 0.3.0", @@ -4187,7 +4187,7 @@ dependencies = [ [[package]] name = "pallet-aleph" -version = "0.5.4" +version = "0.5.5" dependencies = [ "frame-support", "frame-system", @@ -4978,7 +4978,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/aleph-client/Cargo.lock b/aleph-client/Cargo.lock index 34b679cfc2..4471763e83 100644 --- a/aleph-client/Cargo.lock +++ b/aleph-client/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.12.0" +version = "2.13.0" dependencies = [ "anyhow", "async-trait", @@ -2066,7 +2066,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/aleph-client/Cargo.toml b/aleph-client/Cargo.toml index 95f31e96e0..07b890d7ab 100644 --- a/aleph-client/Cargo.toml +++ b/aleph-client/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "aleph_client" -version = "2.12.0" +# TODO bump major version when API stablize +version = "2.13.0" edition = "2021" license = "Apache 2.0" diff --git a/aleph-client/src/aleph_zero.rs b/aleph-client/src/aleph_zero.rs index 2428e75225..f50f584435 100644 --- a/aleph-client/src/aleph_zero.rs +++ b/aleph-client/src/aleph_zero.rs @@ -6353,9 +6353,10 @@ pub mod api { "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, + 223u8, 196u8, 18u8, 234u8, 75u8, 169u8, 31u8, 25u8, 180u8, 189u8, 78u8, + 192u8, 179u8, 27u8, 218u8, 254u8, 245u8, 211u8, 86u8, 33u8, 113u8, + 114u8, 214u8, 133u8, 240u8, 211u8, 232u8, 163u8, 123u8, 98u8, 114u8, + 26u8, ], ) } @@ -6430,9 +6431,10 @@ pub mod api { "FinalityVersion", vec![], [ - 99u8, 158u8, 103u8, 180u8, 128u8, 32u8, 84u8, 110u8, 229u8, 2u8, 3u8, - 114u8, 95u8, 125u8, 230u8, 210u8, 56u8, 85u8, 38u8, 136u8, 49u8, 206u8, - 6u8, 136u8, 193u8, 164u8, 251u8, 60u8, 125u8, 91u8, 205u8, 144u8, + 134u8, 19u8, 94u8, 247u8, 125u8, 18u8, 148u8, 160u8, 167u8, 235u8, + 174u8, 4u8, 107u8, 69u8, 55u8, 187u8, 249u8, 13u8, 129u8, 99u8, 116u8, + 158u8, 38u8, 29u8, 239u8, 112u8, 150u8, 92u8, 151u8, 197u8, 223u8, + 30u8, ], ) } @@ -19553,9 +19555,9 @@ pub mod api { let runtime_metadata_hash = client.metadata().metadata_hash(&PALLETS); if runtime_metadata_hash != [ - 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, + 129u8, 53u8, 4u8, 85u8, 248u8, 69u8, 122u8, 6u8, 68u8, 150u8, 173u8, 133u8, 118u8, + 19u8, 96u8, 223u8, 153u8, 160u8, 226u8, 156u8, 47u8, 53u8, 206u8, 110u8, 204u8, + 37u8, 67u8, 45u8, 176u8, 126u8, 21u8, 133u8, ] { Err(::subxt::error::MetadataError::IncompatibleMetadata) diff --git a/aleph-client/src/pallets/aleph.rs b/aleph-client/src/pallets/aleph.rs index b68a00f30b..5b3a2441ae 100644 --- a/aleph-client/src/pallets/aleph.rs +++ b/aleph-client/src/pallets/aleph.rs @@ -1,8 +1,9 @@ use codec::Encode; -use primitives::{BlockNumber, SessionIndex}; +use primitives::{BlockNumber, SessionIndex, Version}; use subxt::rpc_params; use crate::{ + api, api::runtime_types::{ pallet_aleph::pallet::Call::set_emergency_finalizer, primitives::app::Public, sp_core::ed25519::Public as EdPublic, @@ -15,6 +16,15 @@ use crate::{ }; // TODO replace docs with link to pallet aleph docs, once they are published +/// Pallet aleph API which does not require sudo. +#[async_trait::async_trait] +pub trait AlephApi { + /// Gets the current finality version. + async fn finality_version(&self, at: Option) -> Version; + /// Gets the finality version for the next session. + async fn next_session_finality_version(&self, at: Option) -> Version; +} + /// Pallet aleph API that requires sudo. #[async_trait::async_trait] pub trait AlephSudoApi { @@ -57,6 +67,23 @@ pub trait AlephRpc { ) -> anyhow::Result<()>; } +#[async_trait::async_trait] +impl AlephApi for C { + async fn finality_version(&self, at: Option) -> Version { + let addrs = api::storage().aleph().finality_version(); + + self.get_storage_entry(&addrs, at).await + } + + async fn next_session_finality_version(&self, hash: Option) -> Version { + let method = "state_call"; + let api_method = "AlephSessionApi_next_session_finality_version"; + let params = rpc_params![api_method, "0x", hash]; + + self.rpc_call(method.to_string(), params).await.unwrap() + } +} + #[async_trait::async_trait] impl AlephSudoApi for RootConnection { async fn set_emergency_finalizer( diff --git a/benches/payout-stakers/Cargo.lock b/benches/payout-stakers/Cargo.lock index ff4de412e7..e76df10353 100644 --- a/benches/payout-stakers/Cargo.lock +++ b/benches/payout-stakers/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.12.0" +version = "2.13.0" dependencies = [ "anyhow", "async-trait", @@ -2175,7 +2175,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/bin/cliain/Cargo.lock b/bin/cliain/Cargo.lock index 36f550dc83..c6bcd8a65c 100644 --- a/bin/cliain/Cargo.lock +++ b/bin/cliain/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.12.0" +version = "2.13.0" dependencies = [ "anyhow", "async-trait", @@ -2466,7 +2466,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/bin/node/src/chain_spec.rs b/bin/node/src/chain_spec.rs index e9a48f522b..269b57208b 100644 --- a/bin/node/src/chain_spec.rs +++ b/bin/node/src/chain_spec.rs @@ -1,12 +1,14 @@ -use std::{collections::HashSet, str::FromStr}; +use std::{collections::HashSet, str::FromStr, string::ToString}; use aleph_primitives::{ staking::{MIN_NOMINATOR_BOND, MIN_VALIDATOR_BOND}, - AuthorityId as AlephId, ADDRESSES_ENCODING, TOKEN, TOKEN_DECIMALS, + AuthorityId as AlephId, Version as FinalityVersion, ADDRESSES_ENCODING, + LEGACY_FINALITY_VERSION, TOKEN, TOKEN_DECIMALS, }; use aleph_runtime::{ - AccountId, AuraConfig, BalancesConfig, ElectionsConfig, GenesisConfig, Perbill, SessionConfig, - SessionKeys, StakingConfig, SudoConfig, SystemConfig, VestingConfig, WASM_BINARY, + AccountId, AlephConfig, AuraConfig, BalancesConfig, ElectionsConfig, GenesisConfig, Perbill, + SessionConfig, SessionKeys, StakingConfig, SudoConfig, SystemConfig, VestingConfig, + WASM_BINARY, }; use libp2p::PeerId; use pallet_staking::{Forcing, StakerStatus}; @@ -136,6 +138,10 @@ pub struct ChainParams { /// Minimum number of stakers before chain enters emergency state. #[arg(long, default_value = "4")] min_validator_count: u32, + + /// Finality version at chain inception. + #[arg(long, default_value = LEGACY_FINALITY_VERSION.to_string())] + finality_version: FinalityVersion, } impl ChainParams { @@ -170,6 +176,10 @@ impl ChainParams { pub fn min_validator_count(&self) -> u32 { self.min_validator_count } + + pub fn finality_version(&self) -> FinalityVersion { + self.finality_version + } } fn system_properties(token_symbol: String) -> serde_json::map::Map { @@ -218,6 +228,7 @@ fn generate_chain_spec_config( let sudo_account = chain_params.sudo_account_id(); let faucet_account = chain_params.faucet_account_id(); let min_validator_count = chain_params.min_validator_count(); + let finality_version = chain_params.finality_version(); Ok(ChainSpec::from_genesis( // Name @@ -233,6 +244,7 @@ fn generate_chain_spec_config( faucet_account.clone(), // Pre-funded faucet account controller_accounts.clone(), // Controller accounts for staking. min_validator_count, + finality_version, ) }, // Bootnodes @@ -335,6 +347,7 @@ fn generate_genesis_config( faucet_account: Option, controller_accounts: Vec, min_validator_count: u32, + finality_version: FinalityVersion, ) -> GenesisConfig { let special_accounts = match faucet_account { Some(faucet_id) => vec![sudo_account.clone(), faucet_id], @@ -398,6 +411,10 @@ fn generate_genesis_config( min_nominator_bond: MIN_NOMINATOR_BOND, ..Default::default() }, + aleph: AlephConfig { + finality_version, + ..Default::default() + }, treasury: Default::default(), vesting: VestingConfig { vesting: vec![] }, nomination_pools: Default::default(), diff --git a/bin/runtime/Cargo.toml b/bin/runtime/Cargo.toml index 238c41da18..98d508007d 100644 --- a/bin/runtime/Cargo.toml +++ b/bin/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleph-runtime" -version = "0.9.0" +version = "0.9.1" authors = ["Cardinal Cryptography"] edition = "2021" homepage = "https://alephzero.org" diff --git a/e2e-tests/Cargo.lock b/e2e-tests/Cargo.lock index 65e4f412e7..1b5bfc1320 100644 --- a/e2e-tests/Cargo.lock +++ b/e2e-tests/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph-e2e-client" -version = "0.10.1" +version = "0.11.0" dependencies = [ "aleph_client", "anyhow", @@ -78,7 +78,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.12.0" +version = "2.13.0" dependencies = [ "anyhow", "async-trait", @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 7f027d28a5..f30feb5f02 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleph-e2e-client" -version = "0.10.1" +version = "0.11.0" edition = "2021" license = "Apache 2.0" diff --git a/e2e-tests/src/finality_version.rs b/e2e-tests/src/finality_version.rs new file mode 100644 index 0000000000..68d4b9fffe --- /dev/null +++ b/e2e-tests/src/finality_version.rs @@ -0,0 +1,37 @@ +use aleph_client::{pallets::aleph::AlephApi, utility::BlocksApi, Connection}; +use log::info; +use primitives::{BlockNumber, Version}; + +pub async fn check_finality_version_at_block( + connection: &Connection, + block_number: BlockNumber, + expected_version: Version, +) { + info!( + "Checking current session finality version for block {}", + block_number + ); + let block_hash = connection + .get_block_hash(block_number) + .await + .expect("Should have been able to get a block hash!"); + let finality_version = connection.finality_version(block_hash).await; + assert_eq!(finality_version, expected_version); +} + +pub async fn check_next_session_finality_version_at_block( + connection: &Connection, + block_number: BlockNumber, + expected_version: Version, +) { + info!( + "Checking next session finality version for block {}", + block_number + ); + let block_hash = connection + .get_block_hash(block_number) + .await + .expect("Should have been able to get a block hash!"); + let next_finality_version = connection.next_session_finality_version(block_hash).await; + assert_eq!(next_finality_version, expected_version); +} diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 1bf9a76cfd..305204ad1d 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -7,6 +7,8 @@ mod config; #[cfg(test)] mod elections; #[cfg(test)] +mod finality_version; +#[cfg(test)] mod rewards; #[cfg(test)] mod synthetic_network; diff --git a/e2e-tests/src/test/finality_version.rs b/e2e-tests/src/test/finality_version.rs new file mode 100644 index 0000000000..06053e4d75 --- /dev/null +++ b/e2e-tests/src/test/finality_version.rs @@ -0,0 +1,223 @@ +use aleph_client::{ + pallets::{aleph::AlephSudoApi, elections::ElectionsApi, session::SessionApi}, + utility::BlocksApi, + waiting::{AlephWaiting, BlockStatus}, + AsConnection, TxStatus, +}; +use anyhow::anyhow; +use log::info; +use primitives::{BlockNumber, SessionIndex, Version, LEGACY_FINALITY_VERSION}; + +use crate::{ + config::setup_test, + finality_version::{ + check_finality_version_at_block, check_next_session_finality_version_at_block, + }, +}; + +const UPGRADE_TO_VERSION: u32 = 1; +const UPGRADE_SESSION: SessionIndex = 3; +const UPGRADE_FINALIZATION_WAIT_SESSIONS: u32 = 3; + +const SESSION_WITH_FINALITY_VERSION_CHANGE: SessionIndex = 4; +const SCHEDULING_OFFSET_SESSIONS: f64 = -2.5; +const CHECK_START_BLOCK: BlockNumber = 0; + +/// Simple test that schedules a version upgrade, awaits it, and checks if the node is still finalizing after the planned upgrade session. +#[tokio::test] +pub async fn schedule_version_change() -> anyhow::Result<()> { + let config = setup_test(); + let connection = config.create_root_connection().await; + let test_case_params = config.test_case_params.clone(); + + let current_session = connection.get_session(None).await; + let version_for_upgrade = test_case_params + .upgrade_to_version + .unwrap_or(UPGRADE_TO_VERSION); + let session_for_upgrade = + current_session + test_case_params.upgrade_session.unwrap_or(UPGRADE_SESSION); + let wait_sessions_after_upgrade = test_case_params + .upgrade_finalization_wait_sessions + .unwrap_or(UPGRADE_FINALIZATION_WAIT_SESSIONS); + let session_after_upgrade = session_for_upgrade + wait_sessions_after_upgrade; + + connection + .schedule_finality_version_change( + version_for_upgrade, + session_for_upgrade, + TxStatus::Finalized, + ) + .await?; + connection + .wait_for_session(session_after_upgrade + 1, BlockStatus::Finalized) + .await; + + let block_number = connection + .get_best_block() + .await? + .ok_or(anyhow!("Failed to retrieve best block number!"))?; + connection + .wait_for_block(|n| n >= block_number, BlockStatus::Finalized) + .await; + + Ok(()) +} + +/// A test that schedules a version upgrade which is supposed to fail, awaits it, and checks if finalization stopped. +/// It's up to the user of this test to ensure that version upgrade will actually break finalization (a non-compatible change in protocol, # updated nodes k is f < k < 2/3n). +#[tokio::test] +pub async fn schedule_doomed_version_change_and_verify_finalization_stopped() -> anyhow::Result<()> +{ + let config = setup_test(); + let connection = config.create_root_connection().await; + let test_case_params = config.test_case_params.clone(); + + let current_session = connection.get_session(None).await; + let version_for_upgrade = test_case_params + .upgrade_to_version + .unwrap_or(UPGRADE_TO_VERSION); + let session_for_upgrade = + current_session + test_case_params.upgrade_session.unwrap_or(UPGRADE_SESSION); + let wait_sessions_after_upgrade = test_case_params + .upgrade_finalization_wait_sessions + .unwrap_or(UPGRADE_FINALIZATION_WAIT_SESSIONS); + let session_after_upgrade = session_for_upgrade + wait_sessions_after_upgrade; + + connection + .schedule_finality_version_change( + version_for_upgrade, + session_for_upgrade, + TxStatus::Finalized, + ) + .await?; + connection + .wait_for_session(session_after_upgrade + 1, BlockStatus::Best) + .await; + + let last_finalized_block = session_for_upgrade * connection.get_session_period().await? - 1; + + let finalized_block_head = connection.get_finalized_block_hash().await?; + let finalized_block = connection.get_block_number(finalized_block_head).await?; + + let finalized_block = match finalized_block { + Some(block) => block, + _ => { + return Err(anyhow::Error::msg( + "somehow no block was finalized (even though we saw one)", + )) + } + }; + + // check if finalization is still behind the upgrade-session + assert!(finalized_block <= last_finalized_block); + + Ok(()) +} + +/// Sets up the test. Waits for block 2.5 sessions ahead of `SESSION_WITH_FINALITY_VERSION_CHANGE`. +/// Schedules a finality version change. Waits for all blocks of session +/// `SESSION_WITH_FINALITY_VERSION_CHANGE` to be finalized. Checks the finality version and the +/// finality version for the next session for all the blocks from block `CHECK_START_BLOCK` +/// until the end of session `SESSION_WITH_FINALITY_VERSION_CHANGE`. +#[tokio::test] +pub async fn finality_version_change() -> anyhow::Result<()> { + let config = setup_test(); + let root_connection = config.create_root_connection().await; + let session_period = root_connection.get_session_period().await?; + + let start_point_in_sessions = + SESSION_WITH_FINALITY_VERSION_CHANGE as f64 + SCHEDULING_OFFSET_SESSIONS; + let scheduling_block = (start_point_in_sessions * session_period as f64) as u32; + let end_block = (SESSION_WITH_FINALITY_VERSION_CHANGE + 1) * session_period - 1; + + let first_incoming_finality_version = LEGACY_FINALITY_VERSION as Version + 1; + + info!( + "Finality version check | start block: {} | end block: {}", + CHECK_START_BLOCK, end_block, + ); + info!( + "Version change to be scheduled on block {} for block {}", + scheduling_block, + SESSION_WITH_FINALITY_VERSION_CHANGE * session_period + ); + root_connection + .wait_for_block(|n| n >= scheduling_block, BlockStatus::Finalized) + .await; + + root_connection + .schedule_finality_version_change( + first_incoming_finality_version, + SESSION_WITH_FINALITY_VERSION_CHANGE, + TxStatus::Finalized, + ) + .await?; + + root_connection + .wait_for_block(|n| n >= end_block, BlockStatus::Finalized) + .await; + + let finality_change_block = SESSION_WITH_FINALITY_VERSION_CHANGE * session_period; + let last_block_with_default_next_session_finality_version = + finality_change_block - session_period - 1; + + info!( + "Checking default finality versions. Blocks {} to {}", + CHECK_START_BLOCK, last_block_with_default_next_session_finality_version + ); + for block in CHECK_START_BLOCK..(last_block_with_default_next_session_finality_version + 1) { + check_finality_version_at_block( + root_connection.as_connection(), + block, + LEGACY_FINALITY_VERSION as Version, + ) + .await; + check_next_session_finality_version_at_block( + root_connection.as_connection(), + block, + LEGACY_FINALITY_VERSION as Version, + ) + .await; + } + + info!( + "Checking finality versions for session prior to the change. Blocks {} to {}", + last_block_with_default_next_session_finality_version + 1, + finality_change_block - 1 + ); + for block in (last_block_with_default_next_session_finality_version + 1)..finality_change_block + { + check_finality_version_at_block( + root_connection.as_connection(), + block, + LEGACY_FINALITY_VERSION as Version, + ) + .await; + check_next_session_finality_version_at_block( + root_connection.as_connection(), + block, + first_incoming_finality_version, + ) + .await; + } + info!( + "Checking finality versions once the change has come into effect. Blocks {} to {}", + finality_change_block, end_block + ); + for block in finality_change_block..(end_block + 1) { + check_finality_version_at_block( + root_connection.as_connection(), + block, + first_incoming_finality_version, + ) + .await; + check_next_session_finality_version_at_block( + root_connection.as_connection(), + block, + first_incoming_finality_version, + ) + .await; + } + + Ok(()) +} diff --git a/e2e-tests/src/test/mod.rs b/e2e-tests/src/test/mod.rs index 367ae28eda..c5ffd807bc 100644 --- a/e2e-tests/src/test/mod.rs +++ b/e2e-tests/src/test/mod.rs @@ -5,6 +5,10 @@ pub use electing_validators::authorities_are_staking; pub use era_payout::era_payouts_calculated_correctly; pub use era_validators::era_validators; pub use fee::fee_calculation; +pub use finality_version::{ + finality_version_change, schedule_doomed_version_change_and_verify_finalization_stopped, + schedule_version_change, +}; pub use finalization::finalization; pub use high_latency::{high_out_latency_for_all, high_out_latency_for_each_quorum}; pub use rewards::{ @@ -15,9 +19,6 @@ pub use transfer::token_transfer; pub use treasury::{channeling_fee_and_tip, treasury_access}; pub use utility::batch_transactions; pub use validators_rotate::validators_rotate; -pub use version_upgrade::{ - schedule_doomed_version_change_and_verify_finalization_stopped, schedule_version_change, -}; mod adder; mod ban; @@ -25,6 +26,7 @@ mod electing_validators; mod era_payout; mod era_validators; mod fee; +mod finality_version; mod finalization; mod helpers; mod high_latency; @@ -35,4 +37,3 @@ mod treasury; mod utility; mod validators_change; mod validators_rotate; -mod version_upgrade; diff --git a/e2e-tests/src/test/version_upgrade.rs b/e2e-tests/src/test/version_upgrade.rs deleted file mode 100644 index 6bce869b1a..0000000000 --- a/e2e-tests/src/test/version_upgrade.rs +++ /dev/null @@ -1,108 +0,0 @@ -use aleph_client::{ - pallets::{aleph::AlephSudoApi, elections::ElectionsApi, session::SessionApi}, - utility::BlocksApi, - waiting::{AlephWaiting, BlockStatus}, - TxStatus, -}; -use anyhow::anyhow; -use primitives::SessionIndex; - -use crate::config::setup_test; - -const UPGRADE_TO_VERSION: u32 = 1; - -const UPGRADE_SESSION: SessionIndex = 3; - -const UPGRADE_FINALIZATION_WAIT_SESSIONS: u32 = 3; - -// Simple test that schedules a version upgrade, awaits it, and checks if node is still finalizing after planned upgrade session. -#[tokio::test] -pub async fn schedule_version_change() -> anyhow::Result<()> { - let config = setup_test(); - let connection = config.create_root_connection().await; - let test_case_params = config.test_case_params.clone(); - - let current_session = connection.get_session(None).await; - let version_for_upgrade = test_case_params - .upgrade_to_version - .unwrap_or(UPGRADE_TO_VERSION); - let session_for_upgrade = - current_session + test_case_params.upgrade_session.unwrap_or(UPGRADE_SESSION); - let wait_sessions_after_upgrade = test_case_params - .upgrade_finalization_wait_sessions - .unwrap_or(UPGRADE_FINALIZATION_WAIT_SESSIONS); - let session_after_upgrade = session_for_upgrade + wait_sessions_after_upgrade; - - connection - .schedule_finality_version_change( - version_for_upgrade, - session_for_upgrade, - TxStatus::Finalized, - ) - .await?; - connection - .wait_for_session(session_after_upgrade + 1, BlockStatus::Finalized) - .await; - - let block_number = connection - .get_best_block() - .await? - .ok_or(anyhow!("Failed to retrieve best block number!"))?; - connection - .wait_for_block(|n| n >= block_number, BlockStatus::Finalized) - .await; - - Ok(()) -} - -// A test that schedules a version upgrade which is supposed to fail, awaits it, and checks if finalization stopped. -// It's up to the user of this test to ensure that version upgrade will actually break finalization (non-compatible change in protocol, # updated nodes k is f < k < 2/3n). -#[tokio::test] -pub async fn schedule_doomed_version_change_and_verify_finalization_stopped() -> anyhow::Result<()> -{ - let config = setup_test(); - let connection = config.create_root_connection().await; - let test_case_params = config.test_case_params.clone(); - - let current_session = connection.get_session(None).await; - let version_for_upgrade = test_case_params - .upgrade_to_version - .unwrap_or(UPGRADE_TO_VERSION); - let session_for_upgrade = - current_session + test_case_params.upgrade_session.unwrap_or(UPGRADE_SESSION); - let wait_sessions_after_upgrade = test_case_params - .upgrade_finalization_wait_sessions - .unwrap_or(UPGRADE_FINALIZATION_WAIT_SESSIONS); - let session_after_upgrade = session_for_upgrade + wait_sessions_after_upgrade; - - connection - .schedule_finality_version_change( - version_for_upgrade, - session_for_upgrade, - TxStatus::Finalized, - ) - .await?; - connection - .wait_for_session(session_after_upgrade + 1, BlockStatus::Best) - .await; - - let last_finalized_block = session_for_upgrade * connection.get_session_period().await? - 1; - - let connection = connection; - let finalized_block_head = connection.get_finalized_block_hash().await?; - let finalized_block = connection.get_block_number(finalized_block_head).await?; - - let finalized_block = match finalized_block { - Some(block) => block, - _ => { - return Err(anyhow::Error::msg( - "somehow no block was finalized (even though we saw one)", - )) - } - }; - - // check if finalization is still behind the upgrade-session - assert!(finalized_block <= last_finalized_block); - - Ok(()) -} diff --git a/finality-aleph/Cargo.toml b/finality-aleph/Cargo.toml index cd2dae041c..b40e86b6f3 100644 --- a/finality-aleph/Cargo.toml +++ b/finality-aleph/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "finality-aleph" -version = "0.6.0" +version = "0.6.1" authors = ["Cardinal Cryptography"] edition = "2021" license = "Apache 2.0" diff --git a/finality-aleph/src/abft/current.rs b/finality-aleph/src/abft/current.rs index c2302b877f..8a2fb2d474 100644 --- a/finality-aleph/src/abft/current.rs +++ b/finality-aleph/src/abft/current.rs @@ -1,3 +1,4 @@ +pub use aleph_primitives::CURRENT_FINALITY_VERSION as VERSION; use current_aleph_bft::{default_config, Config, LocalIO, Terminator}; use log::debug; use sp_blockchain::HeaderBackend; @@ -16,9 +17,6 @@ use crate::{ CurrentNetworkData, Hasher, Keychain, NodeIndex, SessionId, SignatureSet, UnitCreationDelay, }; -/// Version of the current abft -pub const VERSION: u16 = 2; - pub fn run_member< B: Block, C: HeaderBackend + Send + 'static, diff --git a/finality-aleph/src/abft/legacy.rs b/finality-aleph/src/abft/legacy.rs index b03e68e7b1..ba3ed40a99 100644 --- a/finality-aleph/src/abft/legacy.rs +++ b/finality-aleph/src/abft/legacy.rs @@ -1,3 +1,4 @@ +pub use aleph_primitives::LEGACY_FINALITY_VERSION as VERSION; use legacy_aleph_bft::{default_config, Config, LocalIO, Terminator}; use log::debug; use sp_blockchain::HeaderBackend; @@ -16,9 +17,6 @@ use crate::{ Keychain, LegacyNetworkData, NodeIndex, SessionId, UnitCreationDelay, }; -/// Version of the legacy abft -pub const VERSION: u16 = 1; - pub fn run_member< B: Block, C: HeaderBackend + Send + 'static, diff --git a/flooder/Cargo.lock b/flooder/Cargo.lock index 1a7a86ab31..8f2c6f859c 100644 --- a/flooder/Cargo.lock +++ b/flooder/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.12.0" +version = "2.13.0" dependencies = [ "anyhow", "async-trait", @@ -2421,7 +2421,7 @@ dependencies = [ [[package]] name = "primitives" -version = "0.5.4" +version = "0.5.5" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/pallets/aleph/Cargo.toml b/pallets/aleph/Cargo.toml index 5b4897431d..4b85e2990f 100644 --- a/pallets/aleph/Cargo.toml +++ b/pallets/aleph/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-aleph" -version = "0.5.4" +version = "0.5.5" authors = ["Cardinal Cryptography"] edition = "2021" license = "Apache 2.0" diff --git a/pallets/aleph/src/lib.rs b/pallets/aleph/src/lib.rs index b3301607d2..06668c4795 100644 --- a/pallets/aleph/src/lib.rs +++ b/pallets/aleph/src/lib.rs @@ -31,14 +31,14 @@ use frame_support::{ traits::{OneSessionHandler, StorageVersion}, }; pub use pallet::*; -use primitives::{SessionIndex, Version, VersionChange}; +use primitives::{ + SessionIndex, Version, VersionChange, DEFAULT_FINALITY_VERSION, LEGACY_FINALITY_VERSION, +}; use sp_std::prelude::*; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); -const DEFAULT_FINALITY_VERSION: Version = 1; - #[frame_support::pallet] pub mod pallet { use frame_support::{pallet_prelude::*, sp_runtime::RuntimeAppPublic}; @@ -48,6 +48,7 @@ pub mod pallet { }; use pallet_session::SessionManager; use pallets_support::StorageMigration; + use sp_std::marker::PhantomData; use super::*; use crate::traits::{NextSessionAuthorityProvider, SessionInfoProvider}; @@ -304,4 +305,27 @@ pub mod pallet { fn on_disabled(_validator_index: u32) {} } + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub finality_version: Version, + pub _marker: PhantomData, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { + finality_version: LEGACY_FINALITY_VERSION as u32, + _marker: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + >::put(&self.finality_version); + } + } } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index d520341812..29cf604fc6 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "primitives" -version = "0.5.4" +version = "0.5.5" authors = ["Cardinal Cryptography"] edition = "2021" license = "Apache 2.0" diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 61753d47cb..857313e39f 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -65,9 +65,17 @@ pub const DEFAULT_COMMITTEE_SIZE: u32 = 4; pub const DEFAULT_BAN_MINIMAL_EXPECTED_PERFORMANCE: Perbill = Perbill::from_percent(0); pub const DEFAULT_BAN_SESSION_COUNT_THRESHOLD: SessionCount = 3; pub const DEFAULT_BAN_REASON_LENGTH: u32 = 300; + pub const DEFAULT_CLEAN_SESSION_COUNTER_DELAY: SessionCount = 960; pub const DEFAULT_BAN_PERIOD: EraIndex = 10; +/// Version returned when no version has been set. +pub const DEFAULT_FINALITY_VERSION: Version = 0; +/// Current version of abft. +pub const CURRENT_FINALITY_VERSION: u16 = LEGACY_FINALITY_VERSION + 1; +/// Legacy version of abft. +pub const LEGACY_FINALITY_VERSION: u16 = 1; + /// Openness of the process of the elections #[derive(Decode, Encode, TypeInfo, Debug, Clone, PartialEq, Eq)] pub enum ElectionOpenness {