Skip to content
Snippets Groups Projects
tests.rs 10.57 KiB
// Copyright 2021 Axiom-Team
//
// This file is part of Substrate-Libre-Currency.
//
// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Substrate-Libre-Currency is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.

use super::*;
use crate::mock::*;
use crate::MemberData;
use frame_support::{assert_err, assert_ok};
use sp_runtime::testing::UintAuthorityId;

const EMPTY: Vec<u64> = Vec::new();

#[test]
fn test_genesis_build() {
    new_test_ext(3).execute_with(|| {
        run_to_block(1);
        // Verify AuthorityMembers state
        assert_eq!(AuthorityMembers::incoming(), EMPTY);
        assert_eq!(AuthorityMembers::online(), vec![3, 6, 9]);
        assert_eq!(AuthorityMembers::outgoing(), EMPTY);
        assert_eq!(
            AuthorityMembers::member(3),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 5,
                owner_key: 3,
            })
        );
        assert_eq!(
            AuthorityMembers::member(6),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 5,
                owner_key: 6,
            })
        );
        assert_eq!(
            AuthorityMembers::member(9),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 5,
                owner_key: 9,
            })
        );

        // Verify Session state
        assert_eq!(Session::current_index(), 0);
        assert_eq!(Session::validators(), vec![3, 6, 9]);
    });
}

#[test]
fn test_new_session_shoud_not_change_authorities_set() {
    new_test_ext(3).execute_with(|| {
        run_to_block(6);

        assert_eq!(Session::current_index(), 1);
        assert_eq!(Session::validators(), vec![3, 6, 9]);
    });
}

#[test]
fn test_max_keys_life_rule() {
    new_test_ext(3).execute_with(|| {
        run_to_block(11);

        assert_eq!(Session::current_index(), 2);
        assert_eq!(Session::validators(), vec![3, 6, 9]);

        // Member 3 and 6 rotate their sessions keys
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(3),
            UintAuthorityId(3).into()
        ),);
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(6),
            UintAuthorityId(6).into()
        ),);

        // Verify state
        assert_eq!(
            AuthorityMembers::member(3),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 7,
                owner_key: 3,
            })
        );
        assert_eq!(
            AuthorityMembers::member(6),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 7,
                owner_key: 6,
            })
        );

        // Member 9 should expire at session 5
        run_to_block(26);
        assert_eq!(Session::current_index(), 5);
        assert_eq!(AuthorityMembers::online(), vec![3, 6]);
        assert_eq!(AuthorityMembers::member(9), None);

        // Member 9 should be "deprogrammed" but still in the authorities set for 1 session
        assert_eq!(Session::queued_keys().len(), 2);
        assert_eq!(Session::queued_keys()[0].0, 3);
        assert_eq!(Session::queued_keys()[1].0, 6);
        assert_eq!(Session::validators(), vec![3, 6, 9]);

        // Member 9 should be **effectively** out at session 6
        run_to_block(31);
        assert_eq!(Session::current_index(), 6);
        assert_eq!(Session::validators(), vec![3, 6]);
    });
}

#[test]
fn test_go_offline() {
    new_test_ext(3).execute_with(|| {
        run_to_block(1);

        // Member 9 should be able to go offline
        assert_ok!(AuthorityMembers::go_offline(Origin::signed(9)),);

        // Verify state
        assert_eq!(AuthorityMembers::incoming(), EMPTY);
        assert_eq!(AuthorityMembers::online(), vec![3, 6, 9]);
        assert_eq!(AuthorityMembers::outgoing(), vec![9]);
        assert_eq!(
            AuthorityMembers::member(9),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 5,
                owner_key: 9,
            })
        );

        // Member 9 should be "deprogrammed" at the next session
        run_to_block(5);
        assert_eq!(
            AuthorityMembers::member(9),
            Some(MemberData {
                expire_on_session: 4,
                must_rotate_keys_before: 5,
                owner_key: 9,
            })
        );
        assert_eq!(AuthorityMembers::members_expire_on(4), vec![9],);
        assert_eq!(Session::current_index(), 1);
        assert_eq!(Session::validators(), vec![3, 6, 9]);
        assert_eq!(Session::queued_keys().len(), 2);
        assert_eq!(Session::queued_keys()[0].0, 3);
        assert_eq!(Session::queued_keys()[1].0, 6);

        // Member 9 should be **effectively** out at session 2
        run_to_block(10);
        assert_eq!(Session::current_index(), 2);
        assert_eq!(Session::validators(), vec![3, 6]);

        // Member 9 should be removed at session 4
        run_to_block(20);
        assert_eq!(Session::current_index(), 4);
        assert_eq!(Session::validators(), vec![3, 6]);
        assert_eq!(AuthorityMembers::members_expire_on(4), EMPTY);
        assert_eq!(AuthorityMembers::member(9), None);
    });
}

#[test]
fn test_go_online() {
    new_test_ext(3).execute_with(|| {
        run_to_block(1);

        // Member 12 should be able to set their session keys
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(12),
            UintAuthorityId(12).into(),
        ));
        assert_eq!(
            AuthorityMembers::member(12),
            Some(MemberData {
                expire_on_session: 2,
                must_rotate_keys_before: 5,
                owner_key: 12,
            })
        );

        // Member 12 should be able to go online
        assert_ok!(AuthorityMembers::go_online(Origin::signed(12)),);

        // Verify state
        assert_eq!(AuthorityMembers::incoming(), vec![12]);
        assert_eq!(AuthorityMembers::online(), vec![3, 6, 9]);
        assert_eq!(AuthorityMembers::outgoing(), EMPTY);
        assert_eq!(
            AuthorityMembers::member(12),
            Some(MemberData {
                expire_on_session: 2,
                must_rotate_keys_before: 5,
                owner_key: 12,
            })
        );

        // Member 12 should be "programmed" at the next session
        run_to_block(5);
        assert_eq!(Session::current_index(), 1);
        assert_eq!(Session::validators(), vec![3, 6, 9]);
        assert_eq!(Session::queued_keys().len(), 4);
        assert_eq!(Session::queued_keys()[0].0, 3);
        assert_eq!(Session::queued_keys()[1].0, 6);
        assert_eq!(Session::queued_keys()[2].0, 9);
        assert_eq!(Session::queued_keys()[3].0, 12);

        // Member 12 should be **effectively** in the authorities set in 2 sessions
        run_to_block(10);
        assert_eq!(Session::current_index(), 2);
        assert_eq!(Session::validators(), vec![3, 6, 9, 12]);
    });
}

#[test]
fn test_too_many_authorities() {
    new_test_ext(3).execute_with(|| {
        run_to_block(1);

        // Member 12 sets their session keys then go online
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(12),
            UintAuthorityId(12).into(),
        ));
        assert_eq!(AuthorityMembers::authorities_counter(), 3);
        assert_ok!(AuthorityMembers::go_online(Origin::signed(12)),);

        // Member 15 can't go online because there is already 4 authorities "planned"
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(15),
            UintAuthorityId(15).into(),
        ));
        assert_eq!(AuthorityMembers::authorities_counter(), 4);
        assert_err!(
            AuthorityMembers::go_online(Origin::signed(15)),
            Error::<Test>::TooManyAuthorities,
        );

        // If member 3 go_offline, member 15 can go_online
        assert_ok!(AuthorityMembers::go_offline(Origin::signed(3)),);
        assert_eq!(AuthorityMembers::authorities_counter(), 3);
        assert_ok!(AuthorityMembers::go_online(Origin::signed(15)),);
        assert_eq!(AuthorityMembers::authorities_counter(), 4);
    });
}

#[test]
fn test_go_online_then_go_offline_in_same_session() {
    new_test_ext(3).execute_with(|| {
        run_to_block(1);

        // Member 12 sets their session keys & go online
        assert_ok!(AuthorityMembers::set_session_keys(
            Origin::signed(12),
            UintAuthorityId(12).into(),
        ));
        assert_ok!(AuthorityMembers::go_online(Origin::signed(12)),);

        run_to_block(2);

        // Member 12 should be able to go offline at the same session to "cancel" their previous
        // action
        assert_ok!(AuthorityMembers::go_offline(Origin::signed(12)),);

        // Verify state
        assert_eq!(AuthorityMembers::incoming(), EMPTY);
        assert_eq!(AuthorityMembers::online(), vec![3, 6, 9]);
        assert_eq!(AuthorityMembers::outgoing(), EMPTY);
        assert_eq!(
            AuthorityMembers::member(12),
            Some(MemberData {
                expire_on_session: 2,
                must_rotate_keys_before: 5,
                owner_key: 12,
            })
        );
    });
}

#[test]
fn test_go_offline_then_go_online_in_same_session() {
    new_test_ext(3).execute_with(|| {
        run_to_block(6);

        // Member 9 go offline
        assert_ok!(AuthorityMembers::go_offline(Origin::signed(9)),);

        run_to_block(7);

        // Member 9 should be able to go online at the same session to "cancel" their previous action
        assert_ok!(AuthorityMembers::go_online(Origin::signed(9)),);

        // Verify state
        assert_eq!(AuthorityMembers::incoming(), EMPTY);
        assert_eq!(AuthorityMembers::online(), vec![3, 6, 9]);
        assert_eq!(AuthorityMembers::outgoing(), EMPTY);
        assert_eq!(
            AuthorityMembers::member(9),
            Some(MemberData {
                expire_on_session: 0,
                must_rotate_keys_before: 5,
                owner_key: 9,
            })
        );
    });
}