authorities stored based on the session hash map
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
		
							parent
							
								
									a00eec9bb9
								
							
						
					
					
						commit
						e73f3855fd
					
				
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -3834,7 +3834,7 @@ dependencies = [ | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ghost-slow-clap" | ||||
| version = "0.3.20" | ||||
| version = "0.3.23" | ||||
| dependencies = [ | ||||
|  "frame-benchmarking", | ||||
|  "frame-support", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "ghost-slow-clap" | ||||
| version = "0.3.21" | ||||
| version = "0.3.23" | ||||
| description = "Applause protocol for the EVM bridge" | ||||
| license.workspace = true | ||||
| authors.workspace = true | ||||
|  | ||||
| @ -18,11 +18,12 @@ benchmarks! { | ||||
|         let receiver = create_account::<T>(); | ||||
|         let amount = minimum_balance + minimum_balance; | ||||
|         let network_id = NetworkIdOf::<T>::default(); | ||||
|         let session_index = T::ValidatorSet::session_index(); | ||||
| 
 | ||||
|         let authorities = vec![T::AuthorityId::generate_pair(None)]; | ||||
|         let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone()) | ||||
|             .map_err(|()| "more than the maximum number of keys provided")?; | ||||
|         Authorities::<T>::put(bounded_authorities); | ||||
|         Authorities::<T>::set(&session_index, bounded_authorities); | ||||
| 
 | ||||
|         let clap = Clap { | ||||
|             session_index: 0, | ||||
| @ -48,17 +49,17 @@ benchmarks! { | ||||
|     } | ||||
| 
 | ||||
|     self_applause { | ||||
|         let session_index = T::ValidatorSet::session_index(); | ||||
|         let authority = T::AuthorityId::generate_pair(Some(vec![69u8])); | ||||
|         let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(vec![authority.clone()]) | ||||
|             .map_err(|()| "more than the maximum number of keys provided")?; | ||||
|         Authorities::<T>::put(bounded_authorities); | ||||
|         Authorities::<T>::set(&session_index, bounded_authorities); | ||||
| 
 | ||||
|         let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance(); | ||||
|         let receiver = create_account::<T>(); | ||||
|         let receiver_clone = receiver.clone(); | ||||
|         let amount = minimum_balance + minimum_balance; | ||||
|         let network_id = NetworkIdOf::<T>::default(); | ||||
|         let session_index = Default::default(); | ||||
|         let transaction_hash = H256::repeat_byte(1u8); | ||||
| 
 | ||||
|         let unique_transaction_hash = <Pallet<T>>::generate_unique_hash( | ||||
|  | ||||
| @ -13,7 +13,7 @@ use frame_support::{ | ||||
|         EstimateNextSessionRotation, ValidatorSet, ValidatorSetWithIdentification, 
 | ||||
|         OneSessionHandler, Get, | ||||
|     }, | ||||
|     BoundedSlice, WeakBoundedVec, | ||||
|     WeakBoundedVec, | ||||
|     
 | ||||
| }; | ||||
| use frame_system::{ | ||||
| @ -325,7 +325,6 @@ pub mod pallet { | ||||
|     pub enum Error<T> { | ||||
|         NotEnoughClaps, | ||||
|         NotAnAuthority, | ||||
|         ClapForWrongSession, | ||||
|         CurrentValidatorIsDisabled, | ||||
|         AlreadyClapped, | ||||
|         UnregisteredClapRemove, | ||||
| @ -371,20 +370,27 @@ pub mod pallet { | ||||
|     >; | ||||
| 
 | ||||
|     #[pallet::storage] | ||||
|     #[pallet::getter(fn keys)] | ||||
|     pub(super) type Authorities<T: Config> = 
 | ||||
|         StorageValue<_, WeakBoundedVec<T::AuthorityId, T::MaxAuthorities>, ValueQuery>; | ||||
|     #[pallet::getter(fn authorities)] | ||||
|     pub(super) type Authorities<T: Config> = StorageMap< | ||||
|         _, | ||||
|         Twox64Concat, | ||||
|         SessionIndex, | ||||
|         WeakBoundedVec<T::AuthorityId, T::MaxAuthorities>, | ||||
|         ValueQuery, | ||||
|     >; | ||||
| 
 | ||||
|     #[pallet::genesis_config] | ||||
|     #[derive(frame_support::DefaultNoBound)] | ||||
|     pub struct GenesisConfig<T: Config> { | ||||
|         pub keys: Vec<T::AuthorityId>, | ||||
|         pub authorities: Vec<T::AuthorityId>, | ||||
|     } | ||||
| 
 | ||||
|     #[pallet::genesis_build] | ||||
|     impl<T: Config> BuildGenesisConfig for GenesisConfig<T> { | ||||
|         fn build(&self) { | ||||
|             Pallet::<T>::initialize_authorities(&self.keys); | ||||
|             if !self.authorities.is_empty() { | ||||
|                 Pallet::<T>::initialize_authorities(self.authorities.clone()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -465,7 +471,7 @@ pub mod pallet { | ||||
| 
 | ||||
|         fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { | ||||
|             if let Call::slow_clap { clap, signature } = call { | ||||
|                 let authorities = Authorities::<T>::get(); | ||||
|                 let authorities = Authorities::<T>::get(&clap.session_index); | ||||
|                 let authority = match authorities.get(clap.authority_index as usize) { | ||||
|                     Some(authority) => authority, | ||||
|                     None => return InvalidTransaction::BadSigner.into(), | ||||
| @ -506,10 +512,7 @@ impl<T: Config> Pallet<T> { | ||||
|     } | ||||
| 
 | ||||
|     fn try_slow_clap(clap: &Clap<T::AccountId, NetworkIdOf<T>, BalanceOf<T>>) -> DispatchResult { | ||||
|         let current_session_index = T::ValidatorSet::session_index(); | ||||
|         ensure!(current_session_index == clap.session_index, Error::<T>::ClapForWrongSession); | ||||
| 
 | ||||
|         let authorities = Authorities::<T>::get(); | ||||
|         let authorities = Authorities::<T>::get(&clap.session_index); | ||||
|         ensure!(authorities.get(clap.authority_index as usize).is_some(), Error::<T>::NotAnAuthority); | ||||
| 
 | ||||
|         let clap_unique_hash = Self::generate_unique_hash(&clap.receiver, &clap.amount, &clap.network_id); | ||||
| @ -632,7 +635,7 @@ impl<T: Config> Pallet<T> { | ||||
| 
 | ||||
|         let enough_authorities = Perbill::from_rational( | ||||
|             ReceivedClaps::<T>::get(&received_claps_key).len() as u32, | ||||
|             Authorities::<T>::get().len() as u32, | ||||
|             Authorities::<T>::get(session_index).len() as u32, | ||||
|         ) > Perbill::from_percent(T::ApplauseThreshold::get()); | ||||
| 
 | ||||
|         ensure!(enough_authorities, Error::<T>::NotEnoughClaps); | ||||
| @ -795,7 +798,8 @@ impl<T: Config> Pallet<T> { | ||||
|     } | ||||
| 
 | ||||
|     fn local_authorities() -> impl Iterator<Item = (u32, T::AuthorityId)> { | ||||
|         let authorities = Authorities::<T>::get(); | ||||
|         let session_index = T::ValidatorSet::session_index(); | ||||
|         let authorities = Authorities::<T>::get(&session_index); | ||||
|         let mut local_authorities = T::AuthorityId::all(); | ||||
|         local_authorities.sort(); | ||||
|         authorities.into_iter().enumerate().filter_map(move |(index, authority)| { | ||||
| @ -920,13 +924,13 @@ impl<T: Config> Pallet<T> { | ||||
|         authority_deviation < Perbill::from_percent(T::OffenceThreshold::get()) | ||||
|     } | ||||
| 
 | ||||
|     fn initialize_authorities(authorities: &[T::AuthorityId]) { | ||||
|         if !authorities.is_empty() { | ||||
|             assert!(Authorities::<T>::get().is_empty(), "Authorities are already initilized!"); | ||||
|             let bounded_authorities = BoundedSlice::<'_, _, T::MaxAuthorities>::try_from(authorities) | ||||
|                 .expect("more than the maximum number of authorities"); | ||||
|             Authorities::<T>::put(bounded_authorities); | ||||
|         }    
 | ||||
|     fn initialize_authorities(authorities: Vec<T::AuthorityId>) { | ||||
|         let session_index = T::ValidatorSet::session_index(); | ||||
|         assert!(Authorities::<T>::get(&session_index).is_empty(), "Authorities are already initilized!"); | ||||
|         let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities) | ||||
|             .expect("more than the maximum number of authorities"); | ||||
|         Authorities::<T>::set(&session_index, bounded_authorities); | ||||
|         ClapsInSession::<T>::set(&session_index, Default::default()); | ||||
|     } | ||||
| 
 | ||||
|     fn calculate_median_claps(session_index: &SessionIndex) -> u32 { | ||||
| @ -952,10 +956,10 @@ impl<T: Config> Pallet<T> { | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(test)] | ||||
|     fn set_test_authorities(authorities: Vec<T::AuthorityId>) { | ||||
|     fn set_test_authorities(session_index: SessionIndex, authorities: Vec<T::AuthorityId>) { | ||||
|         let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities) | ||||
|             .expect("more than the maximum number of authorities"); | ||||
|         Authorities::<T>::put(bounded_authorities); | ||||
|         Authorities::<T>::set(session_index, bounded_authorities); | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(feature = "runtime-benchmarks")] | ||||
| @ -983,23 +987,21 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> { | ||||
|         I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)>, | ||||
|     { | ||||
|         let authorities = validators.map(|x| x.1).collect::<Vec<_>>(); | ||||
|         Self::initialize_authorities(&authorities); | ||||
|         Self::initialize_authorities(authorities); | ||||
|     } | ||||
| 
 | ||||
|     fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, _queued_validators: I) | ||||
|     where | ||||
|         I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)>, | ||||
|     { | ||||
|         let previous_session = T::ValidatorSet::session_index().saturating_sub(1); | ||||
|         let authorities = validators.map(|x| x.1).collect::<Vec<_>>(); | ||||
|         Self::initialize_authorities(&authorities); | ||||
|         ClapsInSession::<T>::set(previous_session, Default::default()); | ||||
|         Self::initialize_authorities(authorities); | ||||
|     } | ||||
| 
 | ||||
|     fn on_before_session_ending() { | ||||
|         let session_index = T::ValidatorSet::session_index(); | ||||
|         let validators = T::ValidatorSet::validators(); | ||||
|         let authorities = Authorities::<T>::get(); | ||||
|         let authorities = Authorities::<T>::get(&session_index); | ||||
| 
 | ||||
|         let median_claps = Self::calculate_median_claps(&session_index); | ||||
| 
 | ||||
|  | ||||
| @ -16,7 +16,6 @@ use sp_staking::{ | ||||
|     SessionIndex, | ||||
| }; | ||||
| 
 | ||||
| #[cfg(feature = "runtime-benchmarks")] | ||||
| use sp_runtime::BuildStorage; | ||||
| 
 | ||||
| use crate as slow_clap; | ||||
| @ -231,12 +230,33 @@ pub fn advance_session() { | ||||
|     let now = System::block_number().max(1); | ||||
|     System::set_block_number(now + 1); | ||||
|     Session::rotate_session(); | ||||
|     let session_index = Session::current_index(); | ||||
| 
 | ||||
|     let authorities = Session::validators() | ||||
|         .into_iter() | ||||
|         .map(UintAuthorityId) | ||||
|         .collect(); | ||||
| 
 | ||||
|     SlowClap::set_test_authorities(authorities); | ||||
|     assert_eq!(Session::current_index(), (now / Period::get()) as u32); | ||||
|     SlowClap::set_test_authorities(session_index, authorities); | ||||
|     assert_eq!(session_index, (now / Period::get()) as u32); | ||||
| } | ||||
| 
 | ||||
| pub fn advance_session_with_authority(authority: u64) { | ||||
|     let now = System::block_number().max(1); | ||||
|     System::set_block_number(now + 1); | ||||
|     Session::rotate_session(); | ||||
| 
 | ||||
|     let session_index = Session::current_index(); | ||||
| 
 | ||||
|     SlowClap::set_test_authorities( | ||||
|         session_index, | ||||
|         vec![ | ||||
|             UintAuthorityId::from(authority), | ||||
|             UintAuthorityId::from(69), | ||||
|             UintAuthorityId::from(420), | ||||
|             UintAuthorityId::from(1337), | ||||
|         ] | ||||
|     ); | ||||
|     assert_eq!(session_index, (now / Period::get()) as u32); | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -2,18 +2,19 @@ | ||||
| 
 | ||||
| use super::*; | ||||
| use crate::mock::*; | ||||
| 
 | ||||
| use frame_support::{assert_err, assert_ok, dispatch}; | ||||
| use sp_core::offchain::{ | ||||
|     testing, | ||||
|     testing::{TestOffchainExt, TestTransactionPoolExt}, | ||||
|     OffchainWorkerExt, OffchainDbExt, TransactionPoolExt, | ||||
| }; | ||||
| use sp_runtime::testing::UintAuthorityId; | ||||
| use sp_runtime::{DispatchError, testing::UintAuthorityId}; | ||||
| 
 | ||||
| use ghost_networks::BridgedInflationCurve; | ||||
| use pallet_staking::EraPayout; | ||||
| 
 | ||||
| const MAX_DEVIATION_DEPTH: u32 = 10; | ||||
| const MAX_DEVIATION_DEPTH: u64 = 10; | ||||
| 
 | ||||
| fn prepare_evm_network( | ||||
|     maybe_network_id: Option<u32>, | ||||
| @ -39,6 +40,34 @@ fn prepare_evm_network( | ||||
|     network_data | ||||
| } | ||||
| 
 | ||||
| fn do_clap_from_first_authority( | ||||
|     session_index: u32, | ||||
|     network_id: u32, | ||||
|     authority: u64, | ||||
| ) -> dispatch::DispatchResult { | ||||
|     let (transaction_hash, receiver, amount) = get_mocked_metadata(); | ||||
|     let clap = Clap { | ||||
|         block_number: 420, | ||||
|         removed: false, | ||||
|         transaction_hash, | ||||
|         session_index, | ||||
|         authority_index: 0, | ||||
|         network_id, | ||||
|         receiver, | ||||
|         amount, | ||||
|     }; | ||||
|     let authority = UintAuthorityId::from(authority); | ||||
|     let signature = authority.sign(&clap.encode()).unwrap(); | ||||
| 
 | ||||
|     SlowClap::pre_dispatch(&crate::Call::slow_clap { | ||||
|         clap: clap.clone(), | ||||
|         signature: signature.clone(), | ||||
|     }) | ||||
|     .map_err(|e| <&'static str>::from(e))?; | ||||
| 
 | ||||
|     SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature) | ||||
| } | ||||
| 
 | ||||
| fn do_clap_from( | ||||
|     session_index: u32, 
 | ||||
|     network_id: u32, 
 | ||||
| @ -325,23 +354,63 @@ fn should_throw_error_if_session_index_is_not_current() { | ||||
|     let (network_id, transaction_hash, unique_transaction_hash) = | ||||
|         generate_unique_hash(None, None, None, None); | ||||
| 
 | ||||
|     let bad_signer = 777; | ||||
|     let bad_signer_id = 5; | ||||
| 
 | ||||
|     new_test_ext().execute_with(|| { | ||||
|         let session_index = advance_session_and_get_index(); | ||||
|         let mut session_and_indexes = Vec::new(); | ||||
| 
 | ||||
|         for deviation in 1..MAX_DEVIATION_DEPTH { | ||||
|             let session_index_up = session_index.saturating_add(deviation); | ||||
|             let session_index_down = session_index.saturating_sub(deviation); | ||||
|             let storage_key_up = (session_index_up, transaction_hash, unique_transaction_hash); | ||||
|             let storage_key_down = (session_index_down, transaction_hash, unique_transaction_hash); | ||||
|             advance_session_with_authority(deviation); | ||||
|             session_and_indexes.push((deviation, Session::current_index())); | ||||
|         } | ||||
| 
 | ||||
|         for chunk in session_and_indexes.chunks(3).into_iter() { | ||||
|             let authority_curr = chunk[1].0; | ||||
|             let authority_prev = chunk[0].0; | ||||
|             let authority_next = chunk[2].0; | ||||
| 
 | ||||
|             let session_index_curr = chunk[1].1; | ||||
|             let session_index_prev = chunk[0].1; | ||||
|             let session_index_next = chunk[2].1; | ||||
| 
 | ||||
|             let storage_key_curr = (session_index_curr, transaction_hash, unique_transaction_hash); | ||||
|             let storage_key_prev = (session_index_prev, transaction_hash, unique_transaction_hash); | ||||
|             let storage_key_next = (session_index_next, transaction_hash, unique_transaction_hash); | ||||
| 
 | ||||
|             assert_claps_info_correct(&storage_key_curr, &session_index_curr, 0); | ||||
|             assert_claps_info_correct(&storage_key_prev, &session_index_prev, 0); | ||||
|             assert_claps_info_correct(&storage_key_next, &session_index_next, 0); | ||||
| 
 | ||||
|             assert_invalid_signing_address(session_index_curr, network_id, bad_signer_id); | ||||
|             assert_invalid_signing_address(session_index_prev, network_id, bad_signer_id); | ||||
|             assert_invalid_signing_address(session_index_prev, network_id, bad_signer_id); | ||||
| 
 | ||||
|             assert_transaction_has_bad_signature(session_index_curr, network_id, bad_signer); | ||||
|             assert_transaction_has_bad_signature(session_index_prev, network_id, bad_signer); | ||||
|             assert_transaction_has_bad_signature(session_index_prev, network_id, bad_signer); | ||||
| 
 | ||||
|             assert_transaction_has_bad_signature(session_index_curr, network_id, authority_prev); | ||||
|             assert_transaction_has_bad_signature(session_index_curr, network_id, authority_next); | ||||
| 
 | ||||
|             assert_transaction_has_bad_signature(session_index_prev, network_id, authority_curr); | ||||
|             assert_transaction_has_bad_signature(session_index_prev, network_id, authority_next); | ||||
| 
 | ||||
|             assert_transaction_has_bad_signature(session_index_next, network_id, authority_prev); | ||||
|             assert_transaction_has_bad_signature(session_index_next, network_id, authority_curr); | ||||
| 
 | ||||
|             assert_claps_info_correct(&storage_key_curr, &session_index_curr, 0); | ||||
|             assert_claps_info_correct(&storage_key_prev, &session_index_prev, 0); | ||||
|             assert_claps_info_correct(&storage_key_next, &session_index_next, 0); | ||||
| 
 | ||||
|             assert_ok!(do_clap_from_first_authority(session_index_curr, network_id, authority_curr)); | ||||
|             assert_ok!(do_clap_from_first_authority(session_index_prev, network_id, authority_prev)); | ||||
|             assert_ok!(do_clap_from_first_authority(session_index_next, network_id, authority_next)); | ||||
| 
 | ||||
|             assert_claps_info_correct(&storage_key_curr, &session_index_curr, 1); | ||||
|             assert_claps_info_correct(&storage_key_prev, &session_index_prev, 1); | ||||
|             assert_claps_info_correct(&storage_key_next, &session_index_next, 1); | ||||
| 
 | ||||
|             assert_claps_info_correct(&storage_key_up, &session_index, 0); | ||||
|             assert_claps_info_correct(&storage_key_down, &session_index, 0); | ||||
|             assert_err!(do_clap_from(session_index_up, network_id, 0, false), 
 | ||||
|                 Error::<Runtime>::ClapForWrongSession); | ||||
|             assert_err!(do_clap_from(session_index_down, network_id, 0, false), 
 | ||||
|                 Error::<Runtime>::ClapForWrongSession); | ||||
|             assert_claps_info_correct(&storage_key_up, &session_index, 0); | ||||
|             assert_claps_info_correct(&storage_key_down, &session_index, 0); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| @ -768,6 +837,24 @@ fn assert_claps_info_correct( | ||||
|     assert_eq!(pallet::ClapsInSession::<Runtime>::get(session_index).len(), index); | ||||
| } | ||||
| 
 | ||||
| fn assert_transaction_has_bad_signature( | ||||
|     session_index: u32, | ||||
|     network_id: u32, | ||||
|     authority: u64, | ||||
| ) { | ||||
|     assert_err!(do_clap_from_first_authority(session_index, network_id, authority), | ||||
|         DispatchError::Other("Transaction has a bad signature")); | ||||
| } | ||||
| 
 | ||||
| fn assert_invalid_signing_address( | ||||
|     session_index: u32, | ||||
|     network_id: u32, | ||||
|     authority_index: u32, | ||||
| ) { | ||||
|     assert_err!(do_clap_from(session_index, network_id, authority_index, false), | ||||
|         DispatchError::Other("Invalid signing address")); | ||||
| } | ||||
| 
 | ||||
| fn get_rpc_endpoint() -> Vec<u8> { | ||||
|     b"https://rpc.endpoint.network.com".to_vec() | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user