#![cfg(feature = "runtime-benchmarks")]

use super::*;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;

use ghost_helpers::networks::NetworkDataBuilder;

fn prepare_pallet<T: Config>(authorities_len: usize) -> (
	PendingDkgAuthorities<ParticipantsBitmap<T>, BlockNumberFor<T>>,
	NetworkCurve,
	T::AuthorityId,
	AuthIndex
) {
    let network_curve = NetworkCurve::Secp256k1;
    let authority = T::AuthorityId::generate_pair(None);

    let authorities = vec![authority.clone(); authorities_len];
    let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
        .expect("more than the maximum number of keys provided");

    QualificationAuthorities::<T>::insert(network_curve, bounded_authorities);

    let network_id = NetworkIdOf::<T>::default();
    let network_data = NetworkDataBuilder::default()
        .with_network_type(NetworkType::Evm)
        .with_network_curve(NetworkCurve::Secp256k1)
        .build();

    T::NetworkDataHandler::register(network_id, network_data)
        .expect("network should be valid for insertion");

    let mut dkg_state = PendingDkgAuthorities::default();
    dkg_state.new_dkg(authorities_len);

    (dkg_state, network_curve, authority, 0)
}

#[benchmarks(where T: Config)]
mod benchmarks {
    use super::*;

    #[benchmark]
    fn register_round0_package() -> Result<(), BenchmarkError> {
        let dummy_hash = ExodusHash::repeat_byte(69);
        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(1);

        dkg_state.next_phase();
        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let round0_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(0)
            .with_dkg_round0(dummy_hash);

        let dkg_package = DkgPackage::Round0(round0_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let expected_hash = Round0Packages::<T>::get(&network_curve, authority_index);
        assert_eq!(expected_hash, dummy_hash);

        Ok(())
    }

    #[benchmark]
    fn register_round1_package(
        c: Linear<4, { T::MaxAuthorities::get() }>
    ) -> Result<(), BenchmarkError> {
        let max_signers = c as AuthIndex;
        let min_signers = get_byzantium_threshold(max_signers);

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();

        dkg_state.insert_index(authority_index);
        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let mut rng = Pallet::<T>::get_offchain_rng(authority_index);

        let (_, public_package) = network_curve.dkg_part1(
            authority_index,
            max_signers,
            min_signers,
            &mut rng,
        ).expect("DKG part1 should work");

        let package_hash = ExodusHash::from(blake2_256(&public_package));
        Round0Packages::<T>::insert(network_curve, authority_index, package_hash);

        let round1_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(0)
            .with_dkg_round1(public_package)
            .expect("Round1 package should be valid");

        let dkg_package = DkgPackage::Round1(round1_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let participants = Round1Packages::<T>::get(&network_curve);
        assert!(participants.contains(authority_index));

        Ok(())
    }

    #[benchmark]
    fn register_encrypted_round2_packages(
        c: Linear<1, { T::MaxAuthorities::get() / 8 }>
    ) -> Result<(), BenchmarkError> {
        let max_signers = (c * 8) as AuthIndex;

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();

        (0..max_signers).for_each(|i| {
            dkg_state.insert_index(i);
        });

        let padded_participants = dkg_state
            .highest_bit::<usize>()
            .map(|bit_pos| bit_pos.saturating_add(1))
            .unwrap_or_default();

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let bitmask_len = padded_participants.div_ceil(8);
        let blob_len = round2_encrypted_package_size(
            padded_participants,
            network_curve.scalar_bytes_len(),
            network_curve.header_bytes_len(),
        );

        let mut bitmask = vec![0u8; bitmask_len];
        let blob = vec![0u8; blob_len];

        (0..max_signers).for_each(|i| {
            if i != authority_index {
                let byte_index = (i / 8) as usize;
                let bit_index = (i % 8) as u8;
                bitmask[byte_index] |= 1 << bit_index;
            }
        });

        let encryption_bundle = BundledPackages { bitmask, blob };

        let round2_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_dkg_round2(encryption_bundle)
            .expect("Round2 package should be valid");

        let dkg_package = DkgPackage::Round2(round2_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let participants = Round2Packages::<T>::get(&network_curve);
        assert!(participants.contains(authority_index));

        Ok(())
    }

    #[benchmark]
    fn register_round3_complaints(
        c: Linear<1, { T::MaxAuthorities::get() / 8 }>
    ) -> Result<(), BenchmarkError> {
        let max_signers = (c * 8) as AuthIndex;

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();

        (0..max_signers).for_each(|i| {
            dkg_state.insert_index(i);
        });

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let bitvec_len = (max_signers + 7) / 8;
        let mut accused_indexes = vec![0u8; bitvec_len as usize];

        (0..max_signers).for_each(|i| {
            if i != authority_index {
                let byte_index = (i / 8) as usize;
                let bit_index = (i % 8) as u8;
                accused_indexes[byte_index] |= 1 << bit_index;
            }
        });

        let round3_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_dkg_round3(accused_indexes)
            .expect("Round3 package should be valid");

        let dkg_package = DkgPackage::Round3(round3_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let complaints = Complaints::<T>::get(&network_curve);
        let my_complaints = complaints.get(&authority_index)
            .expect("Comlpaints should be registered");

        assert_eq!(my_complaints.count_ones::<AuthIndex>(), max_signers - 1);

        Ok(())
    }

    #[benchmark]
    fn register_round4_justifications(
         c: Linear<1, { T::MaxAuthorities::get() / 8 }>
    ) -> Result<(), BenchmarkError> {
        let max_signers = (c * 8) as AuthIndex;

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();

        (0..max_signers).for_each(|i| {
            dkg_state.insert_index(i);
        });

        let padded_participants = dkg_state
            .highest_bit::<usize>()
            .map(|bit_pos| bit_pos.saturating_add(1))
            .unwrap_or_default();

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let bitmask_len = padded_participants.div_ceil(8);
        let blob_len = round2_package_size(
            padded_participants,
            network_curve.scalar_bytes_len(),
            network_curve.header_bytes_len(),
        );

        let mut bitmask = vec![0u8; bitmask_len];
        let blob = vec![0u8; blob_len];

        (0..max_signers).for_each(|i| {
            if i != authority_index {
                let byte_index = (i / 8) as usize;
                let bit_index = (i % 8) as u8;
                bitmask[byte_index] |= 1 << bit_index;
            }
        });

        let justification_bundle = BundledPackages { bitmask, blob };

        let round4_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_dkg_round4(justification_bundle)
            .expect("Round4 package should be valid");

        let dkg_package = DkgPackage::Round4(round4_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let justifications = Justifications::<T>::get(&network_curve);
        let my_justifications = justifications.get(&authority_index)
            .expect("Justifications should be registered");

        assert_eq!(my_justifications.count_ones::<AuthIndex>(), max_signers - 1);

        Ok(())
    }

    #[benchmark]
    fn register_round5_verifying_package() -> Result<(), BenchmarkError> {
        let max_signers = 4 as AuthIndex;

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();

        (0..max_signers).for_each(|i| {
            dkg_state.insert_index(i);
        });

        let dkg_index = dkg_state.get_dkg_index();

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let dummy_merkle_root = ExodusHash::repeat_byte(69);
        let dummy_verifying_key = vec![69u8; network_curve.element_bytes_len()];

        let round5_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_dkg_round5(dummy_verifying_key.clone(), dummy_merkle_root)
            .expect("Round5 package should be valid");

        let dkg_package = DkgPackage::Round5(round5_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let bounded_verifying_key =
            BoundedVec::<u8, ConstU32< { ELEMENT_MAX_BYTES }>>::try_from(
                dummy_verifying_key,
            ).expect("Bounded verifying key should be correct");

        let metadata_hashes = [
            SubstrateBlake2Hasher::hash(dummy_merkle_root.as_ref()),
            SubstrateBlake2Hasher::hash(bounded_verifying_key.as_ref()),
        ];
        let verifying_hash = sequential_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);

        let verification_key = (network_curve, dkg_index, verifying_hash);
        let participants = Verifications::<T>::get(verification_key);
        assert!(participants.contains(authority_index));

        let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, dkg_index);
        assert!(consensus.participants.contains(authority_index));
        assert_eq!(consensus.participants.count_ones::<AuthIndex>(), 1);
        assert_eq!(consensus.merkle_root, dummy_merkle_root);
        assert_eq!(consensus.element_bytes, bounded_verifying_key);

        Ok(())
    }

    #[benchmark]
    fn register_round6_public_share_package(
        c: Linear<1, { T::MaxAuthorities::get().next_power_of_two().trailing_zeros() }>
    ) -> Result<(), BenchmarkError> {
        let computed_max_signers = (1u32 << c) as AuthIndex;
        let constant_max_signers = T::MaxAuthorities::get() as AuthIndex;

        let max_signers = sp_std::cmp::min(computed_max_signers, constant_max_signers);

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();
        dkg_state.next_phase();

        (0..max_signers).for_each(|i| {
            dkg_state.insert_index(i);
        });

        let dkg_index = dkg_state.get_dkg_index();

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);

        let dummy_value = vec![69u8; network_curve.element_bytes_len()];

        let (dummy_merkle_root, dummy_verifying_share, dummy_merkle_proof) =
		    with_ciphersuite!(network_curve, |f| {
                let mut dummy_values = BTreeMap::new();

                for i in 0..max_signers {
                    let non_zero_index = i.saturating_add(1);
                    let identifier: frost_core::Identifier<Ciphersuite> =
                    	frost_core::Identifier::<Ciphersuite>::try_from(non_zero_index)
                    		.expect("Identifier should be created");

                    dummy_values.insert(identifier, dummy_value.clone());
                }

                let merkle_tree =
                	NetworkCurve::build_merkle_tree(
                	    &dummy_values,
                	    |value: &Vec<u8>| Ok(value.clone()),
                    ).expect("Merkle tree for verifying shares should be valid");

                let merkle_root = merkle_tree.last().copied().unwrap();

                let (verifying_share, merkle_proof) = NetworkCurve::generate_merkle_proof_from_tree(
                    &dummy_values,
                    &merkle_tree,
                    authority_index,
                    |value: &Vec<u8>| Ok(value.clone())
                ).expect("Merkle tree proof should be valid");

                (merkle_root, verifying_share, merkle_proof)
            });

        VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |consensus| {
            consensus.participants.insert(authority_index);
            consensus.merkle_root = dummy_merkle_root;
        });

        let round6_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_dkg_round6(dummy_verifying_share.clone(), dummy_merkle_proof)
            .expect("Round6 package should be valid");

        let dkg_package = DkgPackage::Round6(round6_package);

        let signature = authority
            .sign(&dkg_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, dkg_package, signature);

        let participants = VerifyingSharesParticipants::<T>::get(&network_curve, dkg_index);
        assert!(participants.contains(authority_index));

        let bundled_verifying_share =
            BoundedVec::<u8, ConstU32<{ ELEMENT_MAX_BYTES }>>::try_from(
                dummy_verifying_share,
            ).expect("Verifying share should be bundled");

        let verifying_share_key = (network_curve, dkg_index, authority_index);
        assert_eq!(
            VerifyingShares::<T>::get(verifying_share_key).unwrap(),
            bundled_verifying_share,
        );

        Ok(())
    }

    #[benchmark]
    fn register_nonce_commitment() -> Result<(), BenchmarkError> {
        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(1);

        loop {
            if !dkg_state.is_dkg_pending() { break; }
            dkg_state.next_phase();
        }

        dkg_state.insert_index(authority_index);
        let exodus_session = CurrentExodus::<T>::get();

        let dummy_bytes = EvmBytes32::repeat_byte(69);
        let dummy_nonce = vec![0u8; network_curve.element_bytes_len()];
        let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);

        let authorities = QualificationAuthorities::<T>::get(&network_curve);
        let active_dkg: ActivatedState<T> = (&dkg_state).into();
        QualificationDkgState::<T>::insert(&network_curve, dkg_state);
        ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
        ActiveAuthorities::<T>::insert(&network_curve, authorities);
        ExodusRequests::<T>::insert(network_curve, exodus_session, request);

        let nonce_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_exodus_nonce_commitment(
                exodus_session,
                dummy_nonce.clone(),
                dummy_nonce.clone(),
            )
            .expect("Nonce commitment package should be valid");

        let exodus_package = ExodusPackage::NonceCommitment(nonce_package);

        let signature = authority
            .sign(&exodus_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, exodus_package, signature);

        let roast_session = RoastSessions::<T>::get(&exodus_session, authority_index)
            .expect("ROAST session should exist after nonce commitment");

        let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
        assert!(roast_state.nonce_committers.contains(authority_index));
        assert!(!roast_state.group_committers.contains(authority_index));
        assert!(!roast_state.partial_signers.contains(authority_index));

        let registered_nonces = NonceCommitments::<T>::get(
            (exodus_session, roast_session),
            authority_index,
        ).expect("Nonces should be registered during nonce commitment");

        assert_eq!(registered_nonces.hiding, dummy_nonce.clone());
        assert_eq!(registered_nonces.binding, dummy_nonce);

        Ok(())
    }

    #[benchmark]
    fn register_group_commitment() -> Result<(), BenchmarkError> {
        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(1);

        loop {
            if !dkg_state.is_dkg_pending() { break; }
            dkg_state.next_phase();
        }

        dkg_state.insert_index(authority_index);
        let exodus_session = CurrentExodus::<T>::get();

        let dummy_bytes = EvmBytes32::repeat_byte(69);
        let dummy_merkle_root = ExodusHash::repeat_byte(69);
        let dummy_group_commitment = vec![0u8; network_curve.element_bytes_len()];
        let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);

        let authorities = QualificationAuthorities::<T>::get(&network_curve);
        let active_dkg: ActivatedState<T> = (&dkg_state).into();
        QualificationDkgState::<T>::insert(&network_curve, dkg_state);
        ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
        ActiveAuthorities::<T>::insert(&network_curve, authorities);
        ExodusRequests::<T>::insert(network_curve, exodus_session, request);

        let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
        roast_state.status = RoastStatus::GroupCommitments;
        roast_state.nonce_committers.insert(authority_index);

        let roast_session = 3;
        RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
        RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);

        let group_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_exodus_group_commitment(
                exodus_session,
                dummy_group_commitment.clone(),
                dummy_bytes,
            )
            .expect("Group commitment package should be valid");

        let exodus_package = ExodusPackage::GroupCommitment(group_package);

        let signature = authority
            .sign(&exodus_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, exodus_package, signature);

        let bounded_group_commitment =
            BoundedVec::<u8, ConstU32<{ ELEMENT_MAX_BYTES }>>::try_from(
                dummy_group_commitment,
            ).expect("Group commtiment should be valid");

        let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
        assert!(roast_state.nonce_committers.contains(authority_index));
        assert!(roast_state.group_committers.contains(authority_index));

        let consensus = GroupCommitmentsConsensus::<T>::get(exodus_session, roast_session);
        assert!(consensus.participants.contains(authority_index));
        assert_eq!(&consensus.element_bytes, &bounded_group_commitment);
        assert_eq!(consensus.merkle_root, dummy_merkle_root);

        let group_commitment_key = (exodus_session, roast_session, dummy_merkle_root, bounded_group_commitment);
        let participants = GroupCommitters::<T>::get(group_commitment_key);
        assert!(participants.contains(authority_index));

        Ok(())
    }

    #[benchmark]
    fn register_signature_share() -> Result<(), BenchmarkError> {
        let max_signers = T::MaxAuthorities::get();
        let threshold = get_byzantium_threshold(max_signers);

        let (mut dkg_state, network_curve, authority, authority_index) =
            prepare_pallet::<T>(max_signers as usize);

        loop {
            if !dkg_state.is_dkg_pending() { break; }
            dkg_state.next_phase();
        }

        dkg_state.insert_index(authority_index);
        let dkg_index = dkg_state.get_dkg_index();
        let exodus_session = CurrentExodus::<T>::get();

        let mut dummy_element = vec![0u8; network_curve.element_bytes_len()];
        dummy_element[0] = 0x02;
        let g_x_coords = [
            0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac,
            0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07,
            0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9,
            0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98
        ];
        dummy_element[1..33].copy_from_slice(&g_x_coords);

        let dummy_bytes = EvmBytes32::repeat_byte(69);
        let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);

        let mut dummy_scalar = vec![0u8; network_curve.scalar_bytes_len()];
        dummy_scalar[network_curve.scalar_bytes_len() - 1] = 1;

        let dummy_signature_share = dummy_scalar.clone();
        let dummy_binding_factor = dummy_scalar.clone();
        let dummy_group_commitment = dummy_element.clone();

        let (dummy_merkle_root, dummy_merkle_proof) =
            with_ciphersuite!(network_curve, |f| {
                let mut dummy_values = BTreeMap::new();

                for i in 0..threshold {
                    let non_zero_index = (i as AuthIndex).saturating_add(1);
                    let identifier: frost_core::Identifier<Ciphersuite> =
                    	frost_core::Identifier::<Ciphersuite>::try_from(non_zero_index)
                    		.expect("Identifier should be created");

                    dummy_values.insert(identifier, dummy_binding_factor.clone());
                }

                let merkle_tree =
                	NetworkCurve::build_merkle_tree(
                	    &dummy_values,
                	    |value: &Vec<u8>| Ok(value.clone()),
                    ).expect("Merkle tree for binding factor should be valid");

                let merkle_root = merkle_tree.last().copied().unwrap();

                let (_, merkle_proof) =
                	NetworkCurve::generate_merkle_proof_from_tree(
                    	&dummy_values,
                    	&merkle_tree,
                    	authority_index,
                    	|value: &Vec<u8>| Ok(value.clone())
                	).expect("Merkle tree proof should be valid");

                (merkle_root, merkle_proof)
            });

        let authorities = QualificationAuthorities::<T>::get(&network_curve);
        let active_dkg: ActivatedState<T> = (&dkg_state).into();
        let active_dkg_index = active_dkg.get_dkg_index();

        QualificationDkgState::<T>::insert(&network_curve, dkg_state);
        ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
        ActiveAuthorities::<T>::insert(&network_curve, authorities);
        ExodusRequests::<T>::insert(network_curve, exodus_session, request);

        let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
        roast_state.status = RoastStatus::PartialSignatures;
        roast_state.nonce_committers.insert(authority_index);
        roast_state.group_committers.insert(authority_index);

        (0..threshold).for_each(|i| {
            if i as AuthIndex == authority_index { return; }
            roast_state.partial_signers.insert(i);
        });

        let roast_session = 3;
        RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
        RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);

        let bounded_group_commitment = BoundedVec::try_from(dummy_group_commitment).unwrap();
        let dummy_verifying_key = BoundedVec::try_from(dummy_element.clone()).unwrap();

        let dummy_verifying_share = BoundedVec::try_from(dummy_element.clone()).unwrap();
        let dummy_nonce = ExodusSeparatedNonce::new(
            BoundedVec::try_from(dummy_element.clone()).unwrap(),
            BoundedVec::try_from(dummy_element.clone()).unwrap(),
        );

        ActiveVerifyingKey::<T>::insert(&network_curve, dummy_verifying_key);
        VerifyingShares::<T>::insert((&network_curve, active_dkg_index, authority_index), dummy_verifying_share);
        NonceCommitments::<T>::insert((&exodus_session, &roast_session), authority_index, dummy_nonce);

        GroupCommitmentsConsensus::<T>::mutate(&exodus_session, &roast_session, |consensus| {
            consensus.element_bytes = bounded_group_commitment.clone();
            consensus.merkle_root = dummy_merkle_root;
            (0..threshold).for_each(|i| {
                consensus.participants.insert(i);
            });
        });

        let share_package = PackageContext::default()
            .with_network_curve(NetworkCurve::Secp256k1)
            .with_authority_index(authority_index)
            .with_exodus_signature_share(
                exodus_session,
                dummy_signature_share.clone(),
                dummy_merkle_proof,
                dummy_binding_factor
            )
            .expect("Signature share package should be valid");

        let exodus_package = ExodusPackage::SignatureShare(share_package);

        let signature = authority
            .sign(&exodus_package.encode())
            .expect("Signature should be created");

        #[extrinsic_call]
        _(RawOrigin::None, exodus_package, signature);

        let maybe_roast_session = RoastSessions::<T>::get(&exodus_session, authority_index);
        assert!(maybe_roast_session.is_none());

        let scalar_exists = SignatureScalars::<T>::contains_key(&exodus_session, &roast_session);
        let consensus_exists = GroupCommitmentsConsensus::<T>::contains_key(&exodus_session, &roast_session);
        let committers_exists = GroupCommitters::<T>::contains_key((
            &exodus_session,
            &roast_session,
            &dummy_merkle_root,
            &bounded_group_commitment,
        ));

        assert!(!scalar_exists);
        assert!(!consensus_exists);
        assert!(!committers_exists);

        assert!(!ExodusRequests::<T>::contains_key(&network_curve, &exodus_session));
        assert!(ExodusSignedRotations::<T>::contains_key((&exodus_session, NetworkType::Evm), dkg_index));

        Ok(())
    }

    impl_benchmark_test_suite!(
        Pallet,
        crate::mock::new_test_ext_benchmarks(),
        crate::mock::Runtime
    );
}
