diff --git a/pallets/slow-clap/Cargo.toml b/pallets/slow-clap/Cargo.toml index e95b160..bb7ea6f 100644 --- a/pallets/slow-clap/Cargo.toml +++ b/pallets/slow-clap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-slow-clap" -version = "0.3.31" +version = "0.3.32" description = "Applause protocol for the EVM bridge" license.workspace = true authors.workspace = true diff --git a/pallets/slow-clap/src/benchmarking.rs b/pallets/slow-clap/src/benchmarking.rs index cd01549..20ca428 100644 --- a/pallets/slow-clap/src/benchmarking.rs +++ b/pallets/slow-clap/src/benchmarking.rs @@ -3,8 +3,8 @@ use super::*; use frame_benchmarking::v1::*; -use frame_system::RawOrigin; use frame_support::traits::fungible::Inspect; +use frame_system::RawOrigin; pub fn create_account() -> T::AccountId { let account_bytes = Vec::from([1u8; 32]); diff --git a/pallets/slow-clap/src/lib.rs b/pallets/slow-clap/src/lib.rs index 2897465..21572e1 100644 --- a/pallets/slow-clap/src/lib.rs +++ b/pallets/slow-clap/src/lib.rs @@ -3,53 +3,50 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use serde::{Deserializer, Deserialize}; +use serde::{Deserialize, Deserializer}; -pub use pallet::*; use frame_support::{ pallet_prelude::*, traits::{ tokens::fungible::{Inspect, Mutate}, - EstimateNextSessionRotation, ValidatorSet, ValidatorSetWithIdentification, - OneSessionHandler, Get, + EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet, + ValidatorSetWithIdentification, }, WeakBoundedVec, - }; use frame_system::{ offchain::{SendTransactionTypes, SubmitTransaction}, pallet_prelude::*, }; +pub use pallet::*; use sp_core::H256; use sp_runtime::{ - Perbill, RuntimeAppPublic, RuntimeDebug, SaturatedConversion, offchain::{ - self as rt_offchain, HttpError, + self as rt_offchain, storage::{MutateStorageError, StorageRetrievalError, StorageValueRef}, storage_lock::{StorageLock, Time}, + HttpError, }, traits::{BlockNumberProvider, Convert, Saturating}, -}; -use sp_std::{ - vec::Vec, prelude::*, - collections::btree_map::BTreeMap, + Perbill, RuntimeAppPublic, RuntimeDebug, SaturatedConversion, }; use sp_staking::{ offence::{Kind, Offence, ReportOffence}, SessionIndex, }; +use sp_std::{collections::btree_map::BTreeMap, prelude::*, vec::Vec}; use ghost_networks::{ - NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, - NetworkDataMutateHandler, NetworkType, + NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, + NetworkType, }; pub mod weights; pub use crate::weights::WeightInfo; -mod tests; -mod mock; mod benchmarking; +mod mock; +mod tests; pub mod sr25519 { mod app_sr25519 { @@ -113,45 +110,55 @@ struct Log { impl Log { fn is_sufficient(&self) -> bool { - self.transaction_hash.is_some() && - self.block_number.is_some() && - self.topics.len() == NUMBER_OF_TOPICS + self.transaction_hash.is_some() + && self.block_number.is_some() + && self.topics.len() == NUMBER_OF_TOPICS } } pub fn de_string_to_bytes<'de, D>(de: D) -> Result>, D::Error> -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let s: &str = Deserialize::deserialize(de)?; Ok(Some(s.as_bytes().to_vec())) } pub fn de_string_to_u64<'de, D>(de: D) -> Result, D::Error> -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let s: &str = Deserialize::deserialize(de)?; let s = if s.starts_with("0x") { &s[2..] } else { &s }; Ok(u64::from_str_radix(s, 16).ok()) } pub fn de_string_to_u64_pure<'de, D>(de: D) -> Result -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let s: &str = Deserialize::deserialize(de)?; let s = if s.starts_with("0x") { &s[2..] } else { &s }; Ok(u64::from_str_radix(s, 16).unwrap_or_default()) } pub fn de_string_to_h256<'de, D>(de: D) -> Result, D::Error> -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let s: &str = Deserialize::deserialize(de)?; let start_index = if s.starts_with("0x") { 2 } else { 0 }; let h256: Vec<_> = (start_index..s.len()) .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i+2], 16).expect("valid u8 symbol; qed")) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid u8 symbol; qed")) .collect(); Ok(Some(H256::from_slice(&h256))) } pub fn de_string_to_vec_of_bytes<'de, D>(de: D) -> Result>, D::Error> -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let strings: Vec<&str> = Deserialize::deserialize(de)?; Ok(strings .iter() @@ -159,25 +166,31 @@ where D: Deserializer<'de> { let start_index = if s.starts_with("0x") { 2 } else { 0 }; (start_index..s.len()) .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i+2], 16).expect("valid u8 symbol; qed")) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("valid u8 symbol; qed")) .collect::>() }) .collect::>>()) } pub fn de_string_to_btree_map<'de, D>(de: D) -> Result, D::Error> -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ let s: &str = Deserialize::deserialize(de)?; let start_index = if s.starts_with("0x") { 2 } else { 0 }; - Ok(BTreeMap::from_iter((start_index..s.len()) - .step_by(64) - .map(|i| ( - u128::from_str_radix(&s[i..i+32], 16).expect("valid u8 symbol; qed"), - u128::from_str_radix(&s[i+32..i+64], 16).expect("valid u8 symbol; qed"), - )))) + Ok(BTreeMap::from_iter((start_index..s.len()).step_by(64).map( + |i| { + ( + u128::from_str_radix(&s[i..i + 32], 16).expect("valid u8 symbol; qed"), + u128::from_str_radix(&s[i + 32..i + 64], 16).expect("valid u8 symbol; qed"), + ) + }, + ))) } -#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[derive( + RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo, MaxEncodedLen, +)] pub struct Clap { pub session_index: SessionIndex, pub authority_index: AuthIndex, @@ -243,12 +256,10 @@ impl core::fmt::Debug for OffchainErr { } } -pub type NetworkIdOf = - <::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId; +pub type NetworkIdOf = <::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId; -pub type BalanceOf = <::Currency as Inspect< - ::AccountId, ->>::Balance; +pub type BalanceOf = + <::Currency as Inspect<::AccountId>>::Balance; pub type ValidatorId = <::ValidatorSet as ValidatorSet< ::AccountId, @@ -277,7 +288,7 @@ pub mod pallet { #[pallet::config] pub trait Config: SendTransactionTypes> + frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type AuthorityId: Member + type AuthorityId: Member + Parameter + RuntimeAppPublic + Ord @@ -287,9 +298,9 @@ pub mod pallet { type NextSessionRotation: EstimateNextSessionRotation>; type ValidatorSet: ValidatorSetWithIdentification; type Currency: Inspect + Mutate; - type NetworkDataHandler: NetworkDataBasicHandler + - NetworkDataInspectHandler + - NetworkDataMutateHandler>; + type NetworkDataHandler: NetworkDataBasicHandler + + NetworkDataInspectHandler + + NetworkDataMutateHandler>; type BlockNumberProvider: BlockNumberProvider>; type ReportUnresponsiveness: ReportOffence< Self::AccountId, @@ -299,7 +310,7 @@ pub mod pallet { #[pallet::constant] type MaxAuthorities: Get; - + #[pallet::constant] type ApplauseThreshold: Get; @@ -319,7 +330,9 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { AuthoritiesEquilibrium, - SomeAuthoritiesTrottling { throttling: Vec> }, + SomeAuthoritiesTrottling { + throttling: Vec>, + }, Clapped { authority_id: AuthIndex, network_id: NetworkIdOf, @@ -357,9 +370,9 @@ pub mod pallet { NMapKey, ), BoundedBTreeSet, - ValueQuery + ValueQuery, >; - + #[pallet::storage] #[pallet::getter(fn applauses_for_transaction)] pub(super) type ApplausesForTransaction = StorageNMap< @@ -370,7 +383,7 @@ pub mod pallet { NMapKey, ), bool, - ValueQuery + ValueQuery, >; #[pallet::storage] @@ -449,16 +462,18 @@ pub mod pallet { impl Hooks> for Pallet { fn offchain_worker(now: BlockNumberFor) { match Self::start_slow_clapping(now) { - Ok(iter) => for result in iter.into_iter() { - if let Err(e) = result { - log::info!( - target: LOG_TARGET, - "👏 Skipping slow clap at {:?}: {:?}", - now, - e, - ) + Ok(iter) => { + for result in iter.into_iter() { + if let Err(e) = result { + log::info!( + target: LOG_TARGET, + "👏 Skipping slow clap at {:?}: {:?}", + now, + e, + ) + } } - }, + } Err(e) => log::info!( target: LOG_TARGET, "👏 Could not start slow clap at {:?}: {:?}", @@ -481,9 +496,8 @@ pub mod pallet { None => return InvalidTransaction::BadSigner.into(), }; - let signature_valid = clap.using_encoded(|encoded_clap| { - authority.verify(&encoded_clap, signature) - }); + let signature_valid = + clap.using_encoded(|encoded_clap| authority.verify(&encoded_clap, signature)); if !signature_valid { return InvalidTransaction::BadProof.into(); @@ -510,7 +524,10 @@ impl Pallet { key } - fn read_persistent_offchain_storage(storage_key: &[u8], default_value: R) -> R { + fn read_persistent_offchain_storage( + storage_key: &[u8], + default_value: R, + ) -> R { StorageValueRef::persistent(&storage_key) .get::() .ok() @@ -556,36 +573,52 @@ impl Pallet { fn try_slow_clap(clap: &Clap, BalanceOf>) -> DispatchResult { let authorities = Authorities::::get(&clap.session_index); - ensure!(authorities.get(clap.authority_index as usize).is_some(), Error::::NotAnAuthority); + ensure!( + authorities.get(clap.authority_index as usize).is_some(), + Error::::NotAnAuthority + ); - let clap_unique_hash = Self::generate_unique_hash(&clap.receiver, &clap.amount, &clap.network_id); - let received_claps_key = (clap.session_index, &clap.transaction_hash, &clap_unique_hash); + let clap_unique_hash = + Self::generate_unique_hash(&clap.receiver, &clap.amount, &clap.network_id); + let received_claps_key = ( + clap.session_index, + &clap.transaction_hash, + &clap_unique_hash, + ); - let number_of_received_claps = ReceivedClaps::::try_mutate(&received_claps_key, |tree_of_claps| { - let number_of_claps = tree_of_claps.len(); - match (tree_of_claps.contains(&clap.authority_index), clap.removed) { - (true, true) => tree_of_claps - .remove(&clap.authority_index) - .then(|| number_of_claps.saturating_sub(1)) - .ok_or(Error::::UnregisteredClapRemove), - (true, false) => Err(Error::::AlreadyClapped), - (false, true) => Err(Error::::UnregisteredClapRemove), - (false, false) => tree_of_claps - .try_insert(clap.authority_index) - .map(|_| number_of_claps.saturating_add(1)) - .map_err(|_| Error::::TooMuchAuthorities), - } - })?; + let number_of_received_claps = + ReceivedClaps::::try_mutate(&received_claps_key, |tree_of_claps| { + let number_of_claps = tree_of_claps.len(); + match (tree_of_claps.contains(&clap.authority_index), clap.removed) { + (true, true) => tree_of_claps + .remove(&clap.authority_index) + .then(|| number_of_claps.saturating_sub(1)) + .ok_or(Error::::UnregisteredClapRemove), + (true, false) => Err(Error::::AlreadyClapped), + (false, true) => Err(Error::::UnregisteredClapRemove), + (false, false) => tree_of_claps + .try_insert(clap.authority_index) + .map(|_| number_of_claps.saturating_add(1)) + .map_err(|_| Error::::TooMuchAuthorities), + } + })?; ClapsInSession::::try_mutate(&clap.session_index, |claps_details| { - if claps_details.get(&clap.authority_index).map(|x| x.disabled).unwrap_or_default() { + if claps_details + .get(&clap.authority_index) + .map(|x| x.disabled) + .unwrap_or_default() + { return Err(Error::::CurrentValidatorIsDisabled); } (*claps_details) .entry(clap.authority_index) .and_modify(|individual| (*individual).claps.saturating_inc()) - .or_insert(SessionAuthorityInfo { claps: 1u32, disabled: false }); + .or_insert(SessionAuthorityInfo { + claps: 1u32, + disabled: false, + }); Ok(()) })?; @@ -598,18 +631,18 @@ impl Pallet { amount: clap.amount, }); - let enough_authorities = Perbill::from_rational( - number_of_received_claps as u32, - authorities.len() as u32, - ) > Perbill::from_percent(T::ApplauseThreshold::get()); + let enough_authorities = + Perbill::from_rational(number_of_received_claps as u32, authorities.len() as u32) + > Perbill::from_percent(T::ApplauseThreshold::get()); if enough_authorities { - let _ = Self::try_applause(&clap, &received_claps_key) - .inspect_err(|error_msg| log::info!( + let _ = Self::try_applause(&clap, &received_claps_key).inspect_err(|error_msg| { + log::info!( target: LOG_TARGET, "👏 Could not applause because of: {:?}", error_msg, - )); + ) + }); } Ok(()) @@ -621,7 +654,7 @@ impl Pallet { ) -> DispatchResult { ApplausesForTransaction::::try_mutate(received_claps_key, |is_applaused| { if *is_applaused || T::NetworkDataHandler::is_nullification_period() { - return Ok(()) + return Ok(()); } let commission = T::NetworkDataHandler::get(&clap.network_id) @@ -630,18 +663,16 @@ impl Pallet { .mul_ceil(clap.amount); let final_amount = clap.amount.saturating_sub(commission); - let _ = T::NetworkDataHandler::increase_gatekeeper_amount(&clap.network_id, &clap.amount) - .map_err(|_| Error::::CouldNotIncreaseGatekeeperAmount)?; + let _ = + T::NetworkDataHandler::increase_gatekeeper_amount(&clap.network_id, &clap.amount) + .map_err(|_| Error::::CouldNotIncreaseGatekeeperAmount)?; let _ = T::NetworkDataHandler::accumulate_incoming_imbalance(&final_amount) .map_err(|_| Error::::CouldNotAccumulateIncomingImbalance)?; let _ = T::NetworkDataHandler::accumulate_commission(&commission) .map_err(|_| Error::::CouldNotAccumulateCommission)?; if final_amount > T::Currency::minimum_balance() { - T::Currency::mint_into( - &clap.receiver, - final_amount - )?; + T::Currency::mint_into(&clap.receiver, final_amount)?; } *is_applaused = true; @@ -662,7 +693,7 @@ impl Pallet { transaction_hash: H256, receiver: T::AccountId, amount: BalanceOf, - ) -> DispatchResult{ + ) -> DispatchResult { let clap_unique_hash = Self::generate_unique_hash(&receiver, &amount, &network_id); let received_claps_key = (session_index, &transaction_hash, &clap_unique_hash); @@ -689,7 +720,7 @@ impl Pallet { } fn start_slow_clapping( - block_number: BlockNumberFor + block_number: BlockNumberFor, ) -> OffchainResult>> { sp_io::offchain::is_validator() .then(|| ()) @@ -698,10 +729,13 @@ impl Pallet { let session_index = T::ValidatorSet::session_index(); let networks_len = T::NetworkDataHandler::iter().count(); let network_in_use = T::NetworkDataHandler::iter() - .nth(block_number.into() - .as_usize() - .checked_rem(networks_len) - .unwrap_or_default()) + .nth( + block_number + .into() + .as_usize() + .checked_rem(networks_len) + .unwrap_or_default(), + ) .ok_or(OffchainErr::NoStoredNetworks)?; let network_id_encoded = network_in_use.0.encode(); @@ -714,40 +748,47 @@ impl Pallet { ); let network_lock_key = Self::create_storage_key(b"network-lock-", &network_id_encoded); - let block_until = rt_offchain::Duration::from_millis(networks_len as u64 * FETCH_TIMEOUT_PERIOD); + let block_until = + rt_offchain::Duration::from_millis(networks_len as u64 * FETCH_TIMEOUT_PERIOD); let mut network_lock = StorageLock::