Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add e2e tests for permissionless election #702

Merged
merged 19 commits into from
Dec 8, 2022
Merged
16 changes: 16 additions & 0 deletions .github/workflows/e2e-tests-main-devnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,21 @@ jobs:
follow-up-finalization-check: true
timeout-minutes: 15

run-e2e-permissionless-ban:
needs: [ build-test-docker, build-test-client ]
name: Run permissionless ban 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: permissionless_ban
follow-up-finalization-check: true
timeout-minutes: 15

run-e2e-version-upgrade:
needs: [build-test-docker, build-test-client]
name: Run basic (positive) version-upgrade test
Expand Down Expand Up @@ -642,6 +657,7 @@ jobs:
run-e2e-ban-counter-clearing,
run-e2e-ban-threshold,
run-e2e-version-upgrade,
run-e2e-permissionless-ban,
# run-e2e-failing-version-upgrade,
# run-e2e-version-upgrade-catchup,
]
Expand Down
21 changes: 19 additions & 2 deletions aleph-client/src/pallets/elections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use crate::{
pallet_elections::pallet::Call::set_ban_config,
primitives::{BanReason, CommitteeSeats, EraValidators},
},
pallet_elections::pallet::Call::{ban_from_committee, change_validators},
primitives::{BanConfig, BanInfo},
pallet_elections::pallet::Call::{
ban_from_committee, change_validators, set_elections_openness,
},
primitives::{BanConfig, BanInfo, ElectionOpenness},
AccountId, BlockHash,
Call::Elections,
Connection, RootConnection, SudoCall, TxStatus,
Expand Down Expand Up @@ -68,6 +70,11 @@ pub trait ElectionsSudoApi {
ban_reason: Vec<u8>,
status: TxStatus,
) -> anyhow::Result<BlockHash>;
async fn set_election_openness(
&self,
mode: ElectionOpenness,
status: TxStatus,
) -> anyhow::Result<BlockHash>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -212,4 +219,14 @@ impl ElectionsSudoApi for RootConnection {
});
self.sudo_unchecked(call, status).await
}

async fn set_election_openness(
&self,
mode: ElectionOpenness,
status: TxStatus,
) -> anyhow::Result<BlockHash> {
let call = Elections(set_elections_openness { openness: mode });

self.sudo_unchecked(call, status).await
}
}
97 changes: 94 additions & 3 deletions e2e-tests/src/test/ban.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::collections::HashSet;

use aleph_client::{
pallets::{
elections::{ElectionsApi, ElectionsSudoApi},
session::SessionApi,
staking::StakingApi,
staking::{StakingApi, StakingUserApi},
},
primitives::{BanInfo, BanReason},
primitives::{BanInfo, BanReason, CommitteeSeats, ElectionOpenness},
sp_core::bounded::bounded_vec::BoundedVec,
waiting::{BlockStatus, WaitingExt},
SignedConnection, TxStatus,
Expand All @@ -16,14 +18,15 @@ use primitives::{
};

use crate::{
accounts::{get_validator_seed, NodeKeys},
accounts::{account_ids_from_keys, get_validator_seed, NodeKeys},
ban::{
check_ban_config, check_ban_event, check_ban_info_for_validator,
check_underperformed_count_for_sessions, check_underperformed_validator_reason,
check_underperformed_validator_session_count, check_validators, setup_test,
},
config,
rewards::set_invalid_keys_for_validator,
validators::get_test_validators,
};

const SESSIONS_TO_CHECK: SessionCount = 5;
Expand All @@ -50,6 +53,17 @@ async fn disable_validator(validator_address: &str, validator_seed: u32) -> anyh
set_invalid_keys_for_validator(&connection_to_disable).await
}

async fn signed_connection_for_disabled_controller() -> SignedConnection {
let validator_seed = get_validator_seed(VALIDATOR_TO_DISABLE_OVERALL_INDEX);
let stash_controller = NodeKeys::from(validator_seed);
let controller_key_to_disable = stash_controller.controller;
SignedConnection::new(
NODE_TO_DISABLE_ADDRESS.to_string(),
controller_key_to_disable,
)
.await
}

/// Runs a chain, sets up a committee and validators. Sets an incorrect key for one of the
/// validators. Waits for the offending validator to hit the ban threshold of sessions without
/// producing blocks. Verifies that the offending validator has in fact been banned out for the
Expand Down Expand Up @@ -272,6 +286,83 @@ pub async fn clearing_session_count() -> anyhow::Result<()> {
Ok(())
}

/// Setup reserved validators, non_reserved are set to empty vec. Set ban config ban_period to 2.
/// Set Openness to Permissionless.
/// Ban manually one validator. Check if the banned validator is out of the non_reserved and is back
/// after ban period.
#[tokio::test]
pub async fn permissionless_ban() -> anyhow::Result<()> {
let config = config::setup_test();
let root_connection = config.create_root_connection().await;

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: 2,
non_reserved_seats: 2,
};

let validator_to_ban =
&non_reserved_validators[VALIDATOR_TO_DISABLE_NON_RESERVED_INDEX as usize];
let mut non_reserved_without_banned = non_reserved_validators.to_vec();
non_reserved_without_banned.remove(VALIDATOR_TO_DISABLE_NON_RESERVED_INDEX as usize);

let ban_period = 2;
root_connection
.change_validators(
Some(reserved_validators),
Some(non_reserved_validators.clone()),
Some(seats),
TxStatus::InBlock,
)
.await?;
root_connection
.set_election_openness(ElectionOpenness::Permissionless, TxStatus::InBlock)
.await?;
root_connection
.set_ban_config(None, None, None, Some(ban_period), TxStatus::InBlock)
.await?;
root_connection
.ban_from_committee(validator_to_ban.clone(), vec![], TxStatus::InBlock)
.await?;
root_connection
.connection
.wait_for_n_eras(2, BlockStatus::Finalized)
.await;

let without_banned = HashSet::<_>::from_iter(non_reserved_without_banned);
let non_reserved = HashSet::<_>::from_iter(
root_connection
.connection
.get_current_era_validators(None)
.await
.non_reserved,
);
assert_eq!(without_banned, non_reserved);

let signed_connection = signed_connection_for_disabled_controller().await;
// validate again
signed_connection.validate(0, TxStatus::InBlock).await?;
root_connection
.connection
.wait_for_n_eras(2, BlockStatus::Finalized)
.await;
let expected_non_reserved = HashSet::<_>::from_iter(non_reserved_validators);
let non_reserved = HashSet::<_>::from_iter(
root_connection
.connection
.get_current_era_validators(None)
.await
.non_reserved,
);

assert_eq!(expected_non_reserved, non_reserved);

Ok(())
}

/// Runs a chain, sets up a committee and validators. Changes the ban config to require 100%
/// performance. Checks that each validator has all the sessions in which they were chosen for the
/// committee marked as ones in which they underperformed.
Expand Down
4 changes: 3 additions & 1 deletion e2e-tests/src/test/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub use ban::{ban_automatic, ban_manual, ban_threshold, clearing_session_count};
pub use ban::{
ban_automatic, ban_manual, ban_threshold, clearing_session_count, permissionless_ban,
};
pub use electing_validators::authorities_are_staking;
pub use era_payout::era_payouts_calculated_correctly;
pub use era_validators::era_validators;
Expand Down