Skip to content

Commit

Permalink
Add test with dead node
Browse files Browse the repository at this point in the history
  • Loading branch information
mike1729 committed Jan 28, 2025
1 parent 30c24cc commit 2baf242
Showing 1 changed file with 167 additions and 16 deletions.
183 changes: 167 additions & 16 deletions e2e-tests/src/test/performance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@ use std::collections::HashSet;

use aleph_client::{
pallets::{
aleph::AlephApi,
aleph::{AlephApi, AlephSudoApi},
committee_management::CommitteeManagementApi,
elections::{ElectionsApi, ElectionsSudoApi},
session::SessionApi,
},
primitives::{CommitteeSeats, EraValidators},
utility::BlocksApi,
waiting::{BlockStatus, WaitingExt},
AccountId, RootConnection, TxStatus,
waiting::{AlephWaiting, BlockStatus, WaitingExt},
AccountId, RootConnection, SignedConnection, TxStatus,
};
use log::info;
use primitives::{
SessionCount, DEFAULT_FINALITY_BAN_MINIMAL_EXPECTED_PERFORMANCE,
DEFAULT_FINALITY_BAN_SESSION_COUNT_THRESHOLD,
};

use crate::{accounts::account_ids_from_keys, config::Config, validators::get_test_validators};
use crate::{
accounts::{account_ids_from_keys, get_validator_seed, NodeKeys},
config::Config,
rewards::set_invalid_keys_for_validator,
validators::get_test_validators,
};

const RESERVED_SEATS: u32 = 2;
const NON_RESERVED_SEATS: u32 = 2;
const DEAD_INDEX: usize = 1;
const NODE_TO_DISABLE_ADDRESS: &str = "ws://127.0.0.1:9947";
const VALIDATOR_TO_DISABLE_OVERALL_INDEX: u32 = 3;
const ABFT_PERFORMANCE_VERSION: u32 = 5;

#[tokio::test]
async fn all_validators_have_ideal_performance() -> anyhow::Result<()> {
Expand All @@ -31,6 +41,16 @@ async fn all_validators_have_ideal_performance() -> anyhow::Result<()> {
.iter()
.chain(non_reserved_validators.iter());

let current_finality_version = root_connection.finality_version(None).await;
if current_finality_version < ABFT_PERFORMANCE_VERSION {
change_finality_version(&root_connection).await?
}
// In this session first performance metrics are sent, we have to wait some time
// to make sure that we don't check storage before first score is sent.
root_connection
.wait_for_n_sessions(1, BlockStatus::Best)
.await;

check_validators(
&reserved_validators,
&non_reserved_validators,
Expand Down Expand Up @@ -67,6 +87,64 @@ async fn all_validators_have_ideal_performance() -> anyhow::Result<()> {
Ok(())
}

#[tokio::test]
async fn one_validator_is_dead() -> anyhow::Result<()> {
let config = crate::config::setup_test();
let (root_connection, reserved_validators, non_reserved_validators, _) =
setup_test(config).await?;

let current_finality_version = root_connection.finality_version(None).await;
if current_finality_version < ABFT_PERFORMANCE_VERSION {
change_finality_version(&root_connection).await?
}

// In this session first performance metrics are sent, we have to wait some time
// to make sure that we don't check storage before first score is sent.
root_connection
.wait_for_n_sessions(1, BlockStatus::Best)
.await;

check_validators(
&reserved_validators,
&non_reserved_validators,
root_connection.get_current_era_validators(None).await,
);
check_ban_config(
&root_connection,
DEFAULT_FINALITY_BAN_MINIMAL_EXPECTED_PERFORMANCE,
DEFAULT_FINALITY_BAN_SESSION_COUNT_THRESHOLD,
)
.await;

let validator_to_disable = &non_reserved_validators[DEAD_INDEX];

info!("Validator to disable: {}", validator_to_disable);

check_underperformed_validator_session_count(&root_connection, validator_to_disable, 0).await;

disable_validator(
&root_connection,
NODE_TO_DISABLE_ADDRESS,
VALIDATOR_TO_DISABLE_OVERALL_INDEX,
)
.await?;

// Validator has been disabled, let's wait one session in which it's disabled.
let score_session_id = root_connection.get_session(None).await;
root_connection
.wait_for_session(score_session_id + 1, BlockStatus::Best)
.await;

let scores = root_connection
.abft_scores(score_session_id, None)
.await
.unwrap();

assert!(scores.points[DEAD_INDEX] >= 100);

Ok(())
}

async fn setup_test(
config: &Config,
) -> anyhow::Result<(
Expand All @@ -80,23 +158,55 @@ async fn setup_test(
let validator_keys = get_test_validators(config);
let reserved_validators = account_ids_from_keys(&validator_keys.reserved);
let non_reserved_validators = account_ids_from_keys(&validator_keys.non_reserved);

let seats = CommitteeSeats {
reserved_seats: RESERVED_SEATS,
non_reserved_seats: NON_RESERVED_SEATS,
non_reserved_finality_seats: NON_RESERVED_SEATS,
};

root_connection
.change_validators(
Some(reserved_validators.clone()),
Some(non_reserved_validators.clone()),
Some(seats.clone()),
TxStatus::InBlock,
)
.await?;
let current_era_valdators = root_connection.get_current_era_validators(None).await;
let current_committee_seats = root_connection.get_committee_seats(None).await;

let mut send_change_validators_xt = false;
let mut maybe_new_reserved = None;
if current_era_valdators.reserved != reserved_validators {
maybe_new_reserved = Some(reserved_validators.clone());
send_change_validators_xt = true;
}

let mut maybe_new_non_reserved = None;
if current_era_valdators.non_reserved != non_reserved_validators {
maybe_new_non_reserved = Some(non_reserved_validators.clone());
send_change_validators_xt = true;
}

let mut maybe_new_committee_seats = None;
if current_committee_seats != seats {
maybe_new_committee_seats = Some(seats.clone());
send_change_validators_xt = true;
}

root_connection.wait_for_n_eras(2, BlockStatus::Best).await;
if send_change_validators_xt {
info!(
"Changing validators {:?}.",
(
&maybe_new_reserved,
&maybe_new_non_reserved,
&maybe_new_committee_seats
)
);
root_connection
.change_validators(
maybe_new_reserved,
maybe_new_non_reserved,
maybe_new_committee_seats,
TxStatus::InBlock,
)
.await?;

root_connection.wait_for_n_eras(2, BlockStatus::Best).await;
info!("Validators are changed.");
}

Ok((
root_connection,
Expand All @@ -123,6 +233,26 @@ fn check_validators(
era_validators
}

async fn change_finality_version<C: SessionApi + AlephSudoApi + AlephWaiting>(
connection: &C,
) -> anyhow::Result<()> {
info!("Changing finality version to 5.");
let session_for_upgrade = connection.get_session(None).await + 3;
connection
.schedule_finality_version_change(
ABFT_PERFORMANCE_VERSION,
session_for_upgrade,
TxStatus::InBlock,
)
.await?;
connection
.wait_for_session(session_for_upgrade + 1, BlockStatus::Best)
.await;
info!("Finality version is changed.");

Ok(())
}

async fn check_ban_config<C: CommitteeManagementApi>(
connection: &C,
expected_minimal_expected_performance: u16,
Expand Down Expand Up @@ -151,7 +281,28 @@ async fn check_underperformed_validator_session_count<C: CommitteeManagementApi>
.unwrap_or_default();

assert_eq!(
underperformed_validator_session_count,
expected_session_count
underperformed_validator_session_count, expected_session_count,
"{}",
validator
);
}

async fn disable_validator<C: WaitingExt>(
connection: &C,
validator_address: &str,
validator_seed: u32,
) -> anyhow::Result<()> {
let validator_seed = get_validator_seed(validator_seed);
let stash_controller = NodeKeys::from(validator_seed).validator;

// This connection has to be set up with the controller key.
let connection_to_disable = SignedConnection::new(validator_address, stash_controller).await;

set_invalid_keys_for_validator(vec![connection_to_disable]).await?;

// Wait for validator to become disabled
connection.wait_for_n_sessions(3, BlockStatus::Best).await;
info!("Validator {} is disabled.", validator_address);

Ok(())
}

0 comments on commit 2baf242

Please sign in to comment.