Compare commits

..

16 Commits

Author SHA1 Message Date
d45cc9bd13
add latest from_block to logs
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 19:22:48 +03:00
7c57b9ea3f
update chain specs for local testing
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 19:08:43 +03:00
638d31ba28
update casper runtime based on ghost pallets
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 19:07:59 +03:00
c9b4325c04
rustfmt slow-clap pallet
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 19:06:18 +03:00
911db3b974
apply changes from ghost-traits for ExposureListener
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 19:04:24 +03:00
fbc58e350b
conversion function to AccountId added
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 19:03:13 +03:00
b692959369
rustfmt ghost slow clap pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 17:16:07 +03:00
16b933f3ba
rustfmt ghost traits pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 17:15:30 +03:00
ad3de30be3
rustfmt ghost networks pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 17:15:03 +03:00
e3c8e51749
update casper runtime in accordance with new functionality. not final
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 17:12:22 +03:00
d3c5380ba7
updated version of slow clap
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-11-27 17:10:57 +03:00
c3ef933c20
extend networks pallet with avg_block_speed
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 17:10:23 +03:00
954ae66294
bump traits package version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 17:09:10 +03:00
a504d8eb87
trait to get exposure from external pallets such as staking
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 17:08:16 +03:00
eebcc18018
simple bitmap implementation
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-27 17:06:50 +03:00
3be36b6db2
set ghost emoji as prefix for logging
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-11-21 13:49:40 +03:00
25 changed files with 1670 additions and 1218 deletions

10
Cargo.lock generated
View File

@ -1186,7 +1186,7 @@ dependencies = [
[[package]] [[package]]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.33" version = "3.5.34"
dependencies = [ dependencies = [
"casper-runtime-constants", "casper-runtime-constants",
"frame-benchmarking", "frame-benchmarking",
@ -1204,6 +1204,7 @@ dependencies = [
"ghost-runtime-common", "ghost-runtime-common",
"ghost-slow-clap", "ghost-slow-clap",
"ghost-sudo", "ghost-sudo",
"ghost-traits",
"log", "log",
"pallet-alliance", "pallet-alliance",
"pallet-authority-discovery", "pallet-authority-discovery",
@ -3649,7 +3650,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-networks" name = "ghost-networks"
version = "0.1.16" version = "0.1.19"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -3836,12 +3837,13 @@ dependencies = [
[[package]] [[package]]
name = "ghost-slow-clap" name = "ghost-slow-clap"
version = "0.3.47" version = "0.4.1"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
"frame-system", "frame-system",
"ghost-networks", "ghost-networks",
"ghost-traits",
"log", "log",
"pallet-balances", "pallet-balances",
"pallet-session", "pallet-session",
@ -3887,7 +3889,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-traits" name = "ghost-traits"
version = "0.3.23" version = "0.3.25"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"sp-runtime 31.0.1", "sp-runtime 31.0.1",

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package] [workspace.package]
license = "GPL-3.0-only" license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"] authors = ["571nky", "57r37ch", "f4750"]
version = "0.8.2" version = "0.8.3"
edition = "2021" edition = "2021"
homepage = "https://ghostchain.io" homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node" repository = "https://git.ghostchain.io/ghostchain/ghost-node"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-networks" name = "ghost-networks"
version = "0.1.16" version = "0.1.19"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View File

@ -43,6 +43,7 @@ fn prepare_network<T: Config>(
gatekeeper, gatekeeper,
topic_name, topic_name,
network_type: NetworkType::Evm, network_type: NetworkType::Evm,
avg_block_speed: 12,
finality_delay: 69, finality_delay: 69,
rate_limit_delay: 69, rate_limit_delay: 69,
block_distance: 69, block_distance: 69,
@ -239,6 +240,20 @@ benchmarks! {
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network); assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
} }
update_avg_block_speed {
let avg_block_speed = 420;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), avg_block_speed)
verify {
assert_last_event::<T>(Event::NetworkAvgBlockSpeedUpdated {
chain_id: chain_id.clone(), avg_block_speed,
}.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
}
remove_network { remove_network {
let (chain_id, network) = prepare_network::<T>(1, 1, 1); let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::RemoveOrigin::try_successful_origin() let authority = T::RemoveOrigin::try_successful_origin()

View File

@ -38,7 +38,7 @@ mod tests;
pub type BalanceOf<T> = pub type BalanceOf<T> =
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance; <<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub enum NetworkType { pub enum NetworkType {
Evm = 0, Evm = 0,
Utxo = 1, Utxo = 1,
@ -61,6 +61,7 @@ pub struct NetworkData {
pub finality_delay: u64, pub finality_delay: u64,
pub rate_limit_delay: u64, pub rate_limit_delay: u64,
pub block_distance: u64, pub block_distance: u64,
pub avg_block_speed: u64,
pub incoming_fee: u32, pub incoming_fee: u32,
pub outgoing_fee: u32, pub outgoing_fee: u32,
} }
@ -220,6 +221,10 @@ pub mod module {
chain_id: T::NetworkId, chain_id: T::NetworkId,
outgoing_fee: u32, outgoing_fee: u32,
}, },
NetworkAvgBlockSpeedUpdated {
chain_id: T::NetworkId,
avg_block_speed: u64,
},
NetworkRemoved { NetworkRemoved {
chain_id: T::NetworkId, chain_id: T::NetworkId,
}, },
@ -433,6 +438,17 @@ pub mod module {
} }
#[pallet::call_index(11)] #[pallet::call_index(11)]
#[pallet::weight(T::WeightInfo::update_avg_block_speed())]
pub fn update_avg_block_speed(
origin: OriginFor<T>,
chain_id: T::NetworkId,
avg_block_speed: u64,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_avg_block_speed(chain_id, avg_block_speed)
}
#[pallet::call_index(12)]
#[pallet::weight(T::WeightInfo::remove_network())] #[pallet::weight(T::WeightInfo::remove_network())]
pub fn remove_network(origin: OriginFor<T>, chain_id: T::NetworkId) -> DispatchResult { pub fn remove_network(origin: OriginFor<T>, chain_id: T::NetworkId) -> DispatchResult {
T::RemoveOrigin::ensure_origin_or_root(origin)?; T::RemoveOrigin::ensure_origin_or_root(origin)?;
@ -589,7 +605,7 @@ impl<T: Config> Pallet<T> {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult { Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist); ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap(); let net = maybe_network.as_mut().unwrap();
net.network_type = network_type.clone(); net.network_type = network_type;
*maybe_network = Some(net.clone()); *maybe_network = Some(net.clone());
Ok(()) Ok(())
})?; })?;
@ -653,7 +669,7 @@ impl<T: Config> Pallet<T> {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult { Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist); ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap(); let net = maybe_network.as_mut().unwrap();
net.incoming_fee = incoming_fee.clone(); net.incoming_fee = incoming_fee;
*maybe_network = Some(net.clone()); *maybe_network = Some(net.clone());
Ok(()) Ok(())
})?; })?;
@ -671,7 +687,7 @@ impl<T: Config> Pallet<T> {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult { Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist); ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap(); let net = maybe_network.as_mut().unwrap();
net.outgoing_fee = outgoing_fee.clone(); net.outgoing_fee = outgoing_fee;
*maybe_network = Some(net.clone()); *maybe_network = Some(net.clone());
Ok(()) Ok(())
})?; })?;
@ -681,6 +697,24 @@ impl<T: Config> Pallet<T> {
}); });
Ok(()) Ok(())
} }
pub fn do_update_avg_block_speed(
chain_id: T::NetworkId,
avg_block_speed: u64,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
let net = maybe_network.as_mut().unwrap();
net.avg_block_speed = avg_block_speed;
*maybe_network = Some(net.clone());
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkAvgBlockSpeedUpdated {
chain_id,
avg_block_speed,
});
Ok(())
}
} }
impl<T: Config> NetworkDataBasicHandler for Pallet<T> { impl<T: Config> NetworkDataBasicHandler for Pallet<T> {

View File

@ -13,7 +13,6 @@ where
+ sp_std::ops::Shr<Output = Balance> + sp_std::ops::Shr<Output = Balance>
+ sp_std::ops::BitAnd<Balance, Output = Balance>, + sp_std::ops::BitAnd<Balance, Output = Balance>,
{ {
fn zero(&self) -> Balance { fn zero(&self) -> Balance {
0u32.into() 0u32.into()
} }

View File

@ -98,7 +98,7 @@ impl ghost_networks::Config for Test {
type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>; type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>; type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>; type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
type WeightInfo = crate::weights::SubstrateWeight<Test>; type WeightInfo = ();
} }
type Block = frame_system::mocking::MockBlock<Test>; type Block = frame_system::mocking::MockBlock<Test>;

View File

@ -19,6 +19,7 @@ fn prepare_network_data() -> (u32, NetworkData) {
finality_delay: 69, finality_delay: 69,
rate_limit_delay: 69, rate_limit_delay: 69,
block_distance: 69, block_distance: 69,
avg_block_speed: 12_000,
network_type: NetworkType::Evm, network_type: NetworkType::Evm,
gatekeeper: b"0x1234567891234567891234567891234567891234".to_vec(), gatekeeper: b"0x1234567891234567891234567891234567891234".to_vec(),
topic_name: b"0x12345678912345678912345678912345678912345678912345678912345678" topic_name: b"0x12345678912345678912345678912345678912345678912345678912345678"
@ -1882,7 +1883,7 @@ fn check_bridged_inflation_curve_for_big_commissions() {
let (payout, rest) = BridgedInflationCurve::<RewardCurve, Test>::era_payout( let (payout, rest) = BridgedInflationCurve::<RewardCurve, Test>::era_payout(
total_staked_gt_ideal, total_staked_gt_ideal,
total_issuance + amount, total_issuance + amount,
0 0,
); );
assert!(payout < commission); assert!(payout < commission);
assert!(rest < commission); assert!(rest < commission);
@ -1890,7 +1891,7 @@ fn check_bridged_inflation_curve_for_big_commissions() {
let (payout, rest) = BridgedInflationCurve::<RewardCurve, Test>::era_payout( let (payout, rest) = BridgedInflationCurve::<RewardCurve, Test>::era_payout(
total_staked_lt_ideal, total_staked_lt_ideal,
total_issuance + amount, total_issuance + amount,
0 0,
); );
assert!(payout < commission); assert!(payout < commission);
assert!(rest < commission); assert!(rest < commission);

View File

@ -60,6 +60,7 @@ pub trait WeightInfo {
fn update_network_topic_name() -> Weight; fn update_network_topic_name() -> Weight;
fn update_incoming_network_fee() -> Weight; fn update_incoming_network_fee() -> Weight;
fn update_outgoing_network_fee() -> Weight; fn update_outgoing_network_fee() -> Weight;
fn update_avg_block_speed() -> Weight;
fn remove_network() -> Weight; fn remove_network() -> Weight;
} }
@ -209,6 +210,18 @@ impl WeightInfo for () {
} }
/// Storage: `GhostNetworks::Networks` (r:1 w:1) /// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_avg_block_speed() -> Weight {
// Proof Size summary in bytes:
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_579_000 picoseconds.
Weight::from_parts(51_126_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight { fn remove_network() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `302` // Measured: `302`

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-slow-clap" name = "ghost-slow-clap"
version = "0.3.56" version = "0.4.4"
description = "Applause protocol for the EVM bridge" description = "Applause protocol for the EVM bridge"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
@ -28,6 +28,7 @@ sp-io = { workspace = true }
sp-std = { workspace = true } sp-std = { workspace = true }
ghost-networks = { workspace = true } ghost-networks = { workspace = true }
ghost-traits = { workspace = true }
[dev-dependencies] [dev-dependencies]
pallet-balances = { workspace = true } pallet-balances = { workspace = true }

View File

@ -3,7 +3,6 @@
use super::*; use super::*;
use frame_benchmarking::v1::*; use frame_benchmarking::v1::*;
use frame_support::traits::fungible::Inspect;
use frame_system::RawOrigin; use frame_system::RawOrigin;
pub fn create_account<T: Config>() -> T::AccountId { pub fn create_account<T: Config>() -> T::AccountId {
@ -12,16 +11,35 @@ pub fn create_account<T: Config>() -> T::AccountId {
.expect("32 bytes always construct an AccountId32") .expect("32 bytes always construct an AccountId32")
} }
pub fn prepare_evm_network<T: Config>(network_id: NetworkIdOf<T>) {
let network_data = NetworkData {
chain_name: "Ethereum".into(),
default_endpoints: vec![b"https://other.endpoint.network.com".to_vec()],
finality_delay: 69,
avg_block_speed: 69,
rate_limit_delay: 69,
block_distance: 69,
network_type: ghost_networks::NetworkType::Evm,
gatekeeper: b"0x4d224452801ACEd8B2F0aebE155379bb5D594381".to_vec(),
topic_name: b"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".to_vec(),
incoming_fee: 0,
outgoing_fee: 0,
};
let _ = T::NetworkDataHandler::register(network_id, network_data.clone());
}
benchmarks! { benchmarks! {
slow_clap { slow_clap {
let network_id = NetworkIdOf::<T>::default();
prepare_evm_network::<T>(network_id);
let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance(); let minimum_balance = <<T as pallet::Config>::Currency>::minimum_balance();
let receiver = create_account::<T>(); let receiver = create_account::<T>();
let amount = minimum_balance + minimum_balance; let amount = minimum_balance + minimum_balance;
let network_id = NetworkIdOf::<T>::default();
let session_index = T::ValidatorSet::session_index(); let session_index = T::ValidatorSet::session_index();
let transaction_hash = H256::repeat_byte(1u8); let transaction_hash = H256::repeat_byte(1u8);
let args_hash = Pallet::<T>::generate_unique_hash(&receiver, &amount, &network_id);
let authorities = vec![T::AuthorityId::generate_pair(None)]; let authorities = vec![T::AuthorityId::generate_pair(None)];
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone()) let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
@ -39,6 +57,7 @@ benchmarks! {
receiver: receiver.clone(), receiver: receiver.clone(),
amount, amount,
}; };
let args_hash = Pallet::<T>::generate_unique_hash(&clap);
let authority_id = authorities let authority_id = authorities
.get(authority_index as usize) .get(authority_index as usize)
@ -46,16 +65,20 @@ benchmarks! {
let signature = authority_id.sign(&clap.encode()) let signature = authority_id.sign(&clap.encode())
.ok_or("couldn't make signature")?; .ok_or("couldn't make signature")?;
let empty_bitmap = BitMap::new(1);
DisabledAuthorityIndexes::<T>::insert(session_index, empty_bitmap);
assert_eq!(ApplauseDetails::<T>::get(&session_index, &args_hash).is_none(), true);
}: _(RawOrigin::None, clap, signature) }: _(RawOrigin::None, clap, signature)
verify { verify {
let clap_key = (session_index, transaction_hash, args_hash); assert_eq!(ApplauseDetails::<T>::get(&session_index, &args_hash).is_some(), true);
assert_eq!(ReceivedClaps::<T>::get(&clap_key).get(&authority_index).is_some(), true);
assert_eq!(<<T as pallet::Config>::Currency>::total_balance(&receiver), amount); assert_eq!(<<T as pallet::Config>::Currency>::total_balance(&receiver), amount);
} }
commit_block { commit_block {
let session_index = T::ValidatorSet::session_index(); let session_index = T::ValidatorSet::session_index();
let network_id = NetworkIdOf::<T>::default(); let network_id = NetworkIdOf::<T>::default();
prepare_evm_network::<T>(network_id);
let authorities = vec![T::AuthorityId::generate_pair(None)]; let authorities = vec![T::AuthorityId::generate_pair(None)];
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone()) let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities.clone())
@ -68,8 +91,8 @@ benchmarks! {
authority_index, authority_index,
network_id, network_id,
commitment: CommitmentDetails { commitment: CommitmentDetails {
last_registered_block: 69, last_stored_block: 69,
last_seen_block: 420, commits: 420,
last_updated: 1337, last_updated: 1337,
} }
}; };
@ -86,8 +109,8 @@ benchmarks! {
.get(&authority_index) .get(&authority_index)
.cloned() .cloned()
.unwrap_or_default(); .unwrap_or_default();
assert_eq!(stored_commitment.last_registered_block, 69); assert_eq!(stored_commitment.last_stored_block, 69);
assert_eq!(stored_commitment.last_seen_block, 420); assert_eq!(stored_commitment.commits, 1);
assert_eq!(stored_commitment.last_updated, 1337); assert_eq!(stored_commitment.last_updated, 1337);
} }

View File

@ -0,0 +1,117 @@
use codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_core::RuntimeDebug;
use sp_std::collections::btree_map::BTreeMap;
use crate::AuthIndex;
pub type BucketId = u32;
pub type Bucket = u64;
#[derive(Clone, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct BitMap {
buckets: BTreeMap<BucketId, Bucket>,
max_length: u32,
max_value: u32,
}
impl BitMap {
pub fn new(max_value: u32) -> Self {
let mut buckets: BTreeMap<BucketId, Bucket> = Default::default();
let max_length = (max_value >> Self::size_of_bucket()) + 1;
for bucket_id in 0..(max_length) {
buckets.insert(bucket_id, 0);
}
BitMap {
buckets,
max_length,
max_value,
}
}
pub fn size_of_bucket() -> u32 {
(core::mem::size_of::<Bucket>() * 8).trailing_zeros()
}
pub fn iter_buckets(&self) -> impl Iterator<Item = (&BucketId, &Bucket)> {
self.buckets.iter()
}
pub fn exists(&self, index: &AuthIndex) -> bool {
let (bucket_id, bit_position) = self.bitmap_positions(index);
self.buckets
.get(&bucket_id)
.map(|bucket| (bucket >> bit_position) & 1 == 1)
.unwrap_or_default()
}
pub fn set(&mut self, index: AuthIndex) {
let (bucket_id, bit_position) = self.bitmap_positions(&index);
if bucket_id < self.max_length {
let bucket = self.buckets.entry(bucket_id).or_insert(0);
*bucket |= 1 << bit_position;
}
}
pub fn unset(&mut self, index: AuthIndex) {
let (bucket_id, bit_position) = self.bitmap_positions(&index);
if let Some(bucket) = self.buckets.get_mut(&bucket_id) {
*bucket &= !(1 << bit_position);
if *bucket == 0 {
self.buckets.remove(&bucket_id);
}
}
}
pub fn get_bucket(&self, bucket_id: &BucketId) -> Bucket {
self.buckets.get(bucket_id).copied().unwrap_or_default()
}
pub fn count_ones(&self) -> u32 {
let zeros: u32 = self
.iter_buckets()
.map(|(_, bucket)| bucket.count_zeros())
.sum();
let total_bits = self.total_bits();
total_bits.saturating_sub(zeros)
}
pub fn bitor(self, rhs: Self) -> Self {
let (mut base, to_merge) = if self.buckets.len() < rhs.buckets.len() {
(rhs, self)
} else {
(self, rhs)
};
for (key, rhs_value) in to_merge.buckets {
base.buckets
.entry(key)
.and_modify(|lhs_value| *lhs_value |= rhs_value)
.or_insert(rhs_value);
}
base
}
pub fn max_value(&self) -> u32 {
self.max_value
}
fn total_bits(&self) -> u32 {
let size_of_bucket = Self::size_of_bucket();
let bucket_length: u32 = 1 << size_of_bucket;
self.max_length.saturating_mul(bucket_length)
}
fn bitmap_positions(&self, index: &AuthIndex) -> (u32, u32) {
let size_of_bucket = Self::size_of_bucket();
let bucket_length = 1 << size_of_bucket;
let bucket_id = index >> size_of_bucket;
let bit_position = index % bucket_length;
(bucket_id, bit_position)
}
}

View File

@ -54,19 +54,14 @@ impl EvmResponseType {
network_id: NetworkIdOf<T>, network_id: NetworkIdOf<T>,
) -> BlockCommitment<NetworkIdOf<T>> { ) -> BlockCommitment<NetworkIdOf<T>> {
let last_updated = sp_io::offchain::timestamp().unix_millis(); let last_updated = sp_io::offchain::timestamp().unix_millis();
let current_block = match self {
EvmResponseType::BlockNumber(block_number) => *block_number,
EvmResponseType::TransactionLogs(_) => Default::default(),
};
BlockCommitment { BlockCommitment {
session_index, session_index,
authority_index, authority_index,
network_id, network_id,
commitment: CommitmentDetails { commitment: CommitmentDetails {
last_registered_block: from_block, last_stored_block: from_block,
last_seen_block: current_block,
last_updated, last_updated,
commits: 420,
}, },
} }
} }
@ -127,7 +122,7 @@ impl EvmResponseType {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 Found {:?} claps for network {:?}", "👻 Found {:?} claps for network {:?}",
claps_len, claps_len,
network_id, network_id,
); );
@ -138,7 +133,7 @@ impl EvmResponseType {
None => { None => {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 Clap #{} signing failed from authority #{:?} for network {:?}", "👻 Clap #{} signing failed from authority #{:?} for network {:?}",
clap_index, clap_index,
authority_index, authority_index,
network_id, network_id,
@ -157,7 +152,7 @@ impl EvmResponseType {
{ {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 Failed to submit clap #{} from authority #{:?} for network {:?}: {:?}", "👻 Failed to submit clap #{} from authority #{:?} for network {:?}: {:?}",
clap_index, clap_index,
authority_index, authority_index,
network_id, network_id,
@ -198,7 +193,7 @@ impl EvmResponseType {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 New block commitment from authority #{:?} for network {:?}", "👻 New block commitment from authority #{:?} for network {:?}",
authority_index, authority_index,
network_id, network_id,
); );
@ -208,7 +203,7 @@ impl EvmResponseType {
None => { None => {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 Block commitment signing failed from authority #{:?} for network {:?}", "👻 Block commitment signing failed from authority #{:?} for network {:?}",
authority_index, authority_index,
network_id, network_id,
); );
@ -224,7 +219,7 @@ impl EvmResponseType {
if let Err(e) = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into()) { if let Err(e) = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into()) {
log::info!( log::info!(
target: LOG_TARGET, target: LOG_TARGET,
"🧐 Failed to submit block commitment from authority #{:?} for network {:?}: {:?}", "👻 Failed to submit block commitment from authority #{:?} for network {:?}: {:?}",
authority_index, authority_index,
network_id, network_id,
e, e,

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,8 @@ use sp_staking::{
use sp_runtime::BuildStorage; use sp_runtime::BuildStorage;
use crate as slow_clap; use crate::{self as slow_clap};
use crate::{ApplauseListener, Config, EraIndex}; use crate::{Config, ExposureListener};
type Block = frame_system::mocking::MockBlock<Runtime>; type Block = frame_system::mocking::MockBlock<Runtime>;
@ -36,17 +36,13 @@ frame_support::construct_runtime!(
); );
parameter_types! { parameter_types! {
pub static Validators: Option<Vec<u64>> = Some(vec![ pub static FixedValidators: Vec<u64> = vec![0, 1, 2, 3];
1,
2,
3,
]);
} }
pub struct TestSessionManager; pub struct TestSessionManager;
impl pallet_session::SessionManager<u64> for TestSessionManager { impl pallet_session::SessionManager<u64> for TestSessionManager {
fn new_session(_new_index: SessionIndex) -> Option<Vec<u64>> { fn new_session(_new_index: SessionIndex) -> Option<Vec<u64>> {
Validators::mutate(|l| l.take()) Some(FixedValidators::get())
} }
fn end_session(_: SessionIndex) {} fn end_session(_: SessionIndex) {}
fn start_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {}
@ -54,17 +50,14 @@ impl pallet_session::SessionManager<u64> for TestSessionManager {
impl pallet_session::historical::SessionManager<u64, u64> for TestSessionManager { impl pallet_session::historical::SessionManager<u64, u64> for TestSessionManager {
fn new_session(_new_index: SessionIndex) -> Option<Vec<(u64, u64)>> { fn new_session(_new_index: SessionIndex) -> Option<Vec<(u64, u64)>> {
Validators::mutate(|l| { Some(FixedValidators::get().iter().map(|l| (*l, *l)).collect())
l.take()
.map(|validators| validators.iter().map(|v| (*v, *v)).collect())
})
} }
fn end_session(_: SessionIndex) {} fn end_session(_: SessionIndex) {}
fn start_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {}
} }
type IdentificationTuple = (u64, u64); type IdentificationTuple = (u64, u64);
type Offence = crate::ThrottlingOffence<IdentificationTuple>; type Offence = crate::SlowClapOffence<IdentificationTuple>;
parameter_types! { parameter_types! {
pub static Offences: Vec<(Vec<u64>, Offence)> = vec![]; pub static Offences: Vec<(Vec<u64>, Offence)> = vec![];
@ -90,7 +83,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
let mut result = sp_io::TestExternalities::new(t); let mut result = sp_io::TestExternalities::new(t);
result.execute_with(|| { result.execute_with(|| {
for i in 1..=3 { for i in 0..=3 {
System::inc_providers(&i); System::inc_providers(&i);
assert_eq!( assert_eq!(
Session::set_keys(RuntimeOrigin::signed(i), i.into(), vec![],), Session::set_keys(RuntimeOrigin::signed(i), i.into(), vec![],),
@ -176,24 +169,25 @@ impl pallet_balances::Config for Runtime {
type Balance = u64; type Balance = u64;
pub struct TestSomeCoolTrait; pub struct TestExposureListener;
impl ApplauseListener<Balance> for TestSomeCoolTrait impl ExposureListener<Balance, u64> for TestExposureListener
where where
Balance: AtLeast32BitUnsigned + From<u64>, Balance: AtLeast32BitUnsigned + From<u64>,
{ {
fn get_current_era() -> EraIndex { fn get_account_by_index(index: usize) -> Option<u64> {
1 FixedValidators::get().get(index).copied()
} }
fn get_threshold_amount(_era: EraIndex) -> Balance { fn get_total_exposure() -> Balance {
666_666_667u64.into() 1_000_000_000u64.into()
} }
fn get_validator_total_exposure(_era: EraIndex, index: usize) -> Balance { fn get_validator_exposure(validator: &u64) -> Balance {
match index { match validator {
0 => 500_000_000u64, 0 => 250_000_000u64,
1 => 300_000_000u64, 1 => 200_000_000u64,
2 => 200_000_000u64, 2 => 250_000_000u64,
3 => 300_000_000u64,
_ => 0, _ => 0,
} }
.into() .into()
@ -210,14 +204,13 @@ impl Config for Runtime {
type BlockNumberProvider = System; type BlockNumberProvider = System;
type ReportUnresponsiveness = OffenceHandler; type ReportUnresponsiveness = OffenceHandler;
type DisabledValidators = Session; type DisabledValidators = Session;
type ApplauseListener = TestSomeCoolTrait; type ExposureListener = TestExposureListener;
type MaxAuthorities = ConstU32<5>; type MaxAuthorities = ConstU32<5>;
type ApplauseThreshold = ConstU32<50>; type ApplauseThreshold = ConstU32<500_000_000>;
type OffenceThreshold = ConstU32<0>;
type UnsignedPriority = ConstU64<{ 1 << 20 }>; type UnsignedPriority = ConstU64<{ 1 << 20 }>;
type HistoryDepth = HistoryDepth; type HistoryDepth = HistoryDepth;
type MinAuthoritiesNumber = ConstU32<2>; type MinAuthoritiesNumber = ConstU32<1>;
type WeightInfo = (); type WeightInfo = ();
} }
@ -236,32 +229,7 @@ pub fn advance_session() {
let now = System::block_number().max(1); let now = System::block_number().max(1);
System::set_block_number(now + 1); System::set_block_number(now + 1);
Session::rotate_session(); Session::rotate_session();
let session_index = Session::current_index();
let authorities = Session::validators()
.into_iter()
.map(UintAuthorityId)
.collect();
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(); 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); assert_eq!(session_index, (now / Period::get()) as u32);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-traits" name = "ghost-traits"
version = "0.3.23" version = "0.3.26"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View File

@ -0,0 +1,7 @@
use sp_runtime::traits::AtLeast32BitUnsigned;
pub trait ExposureListener<Balance: AtLeast32BitUnsigned, AccountId> {
fn get_account_by_index(index: usize) -> Option<AccountId>;
fn get_total_exposure() -> Balance;
fn get_validator_exposure(index: &AccountId) -> Balance;
}

View File

@ -1,3 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
pub mod exposure;
pub mod networks; pub mod networks;

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.33" version = "3.5.34"
build = "build.rs" build = "build.rs"
description = "Runtime of the Casper Network" description = "Runtime of the Casper Network"
edition.workspace = true edition.workspace = true
@ -88,6 +88,7 @@ ghost-networks = { workspace = true }
ghost-claims = { workspace = true } ghost-claims = { workspace = true }
ghost-slow-clap = { workspace = true } ghost-slow-clap = { workspace = true }
ghost-sudo = { workspace = true } ghost-sudo = { workspace = true }
ghost-traits = { workspace = true }
casper-runtime-constants = { workspace = true } casper-runtime-constants = { workspace = true }
runtime-common = { workspace = true } runtime-common = { workspace = true }
primitives = { workspace = true } primitives = { workspace = true }

View File

@ -1,6 +1,8 @@
use super::*; use super::*;
use frame_support::{dispatch::DispatchResultWithPostInfo, traits::PrivilegeCmp}; use frame_support::{dispatch::DispatchResultWithPostInfo, traits::PrivilegeCmp};
use ghost_traits::exposure::ExposureListener;
use pallet_alliance::{ProposalIndex, ProposalProvider}; use pallet_alliance::{ProposalIndex, ProposalProvider};
use primitives::Balance;
use sp_runtime::DispatchError; use sp_runtime::DispatchError;
use sp_std::{cmp::Ordering, marker::PhantomData}; use sp_std::{cmp::Ordering, marker::PhantomData};
@ -76,6 +78,36 @@ impl PrivilegeCmp<OriginCaller> for EqualOrGreatestRootCmp {
} }
} }
/// Used to get the exposure information out of staking pallet directly.
pub struct StakingExposureListener<T>(PhantomData<T>);
impl<T> ExposureListener<Balance, AccountIdOf<T>> for StakingExposureListener<T>
where
T: pallet_session::Config + pallet_staking::Config + frame_system::Config,
u128: From<T::CurrencyBalance>,
AccountIdOf<T>: From<<T as pallet_session::Config>::ValidatorId>,
{
fn get_account_by_index(index: usize) -> Option<AccountIdOf<T>> {
pallet_session::Pallet::<T>::validators()
.get(index)
.map(|validator| {
let account_id: AccountIdOf<T> = validator.clone().into();
account_id
})
}
fn get_total_exposure() -> Balance {
let era = pallet_staking::Pallet::<T>::current_era().unwrap_or_default();
pallet_staking::Pallet::<T>::eras_total_stake(era).into()
}
fn get_validator_exposure(validator: &AccountIdOf<T>) -> Balance {
let era = pallet_staking::Pallet::<T>::current_era().unwrap_or_default();
pallet_staking::EraInfo::<T>::get_full_exposure(era, validator)
.total
.into()
}
}
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks { pub mod benchmarks {
use super::*; use super::*;

View File

@ -78,7 +78,7 @@ mod genesis_config_presets;
mod impls; mod impls;
mod weights; mod weights;
pub use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp}; pub use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp, StakingExposureListener};
// Governance configuration. // Governance configuration.
pub mod cult; pub mod cult;
@ -1058,10 +1058,9 @@ impl ghost_claims::Config<CultCollectiveInstance> for Runtime {
} }
parameter_types! { parameter_types! {
// will be used in `Perbill::from_percent()` // will be used in `Perbill::from_parts()`
pub const ApplauseThreshold: u32 = 70; pub const ApplauseThreshold: u32 = 500_000_000;
// will be used in `Perbill::from_percent()` pub const MinAuthoritiesNumber: u32 = 5;
pub const OffenceThreshold: u32 = 40;
pub const SlowClapUnsignedPriority: TransactionPriority = TransactionPriority::MAX; pub const SlowClapUnsignedPriority: TransactionPriority = TransactionPriority::MAX;
pub const SlowClapHistoryDepth: sp_staking::SessionIndex = pub const SlowClapHistoryDepth: sp_staking::SessionIndex =
StakingHistoryDepth::get() * SessionsPerEra::get(); StakingHistoryDepth::get() * SessionsPerEra::get();
@ -1071,18 +1070,19 @@ impl ghost_slow_clap::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type AuthorityId = SlowClapId; type AuthorityId = SlowClapId;
type NextSessionRotation = Babe;
type ValidatorSet = Historical; type ValidatorSet = Historical;
type Currency = Balances; type Currency = Balances;
type NetworkDataHandler = GhostNetworks; type NetworkDataHandler = GhostNetworks;
type BlockNumberProvider = System; type BlockNumberProvider = System;
type ReportUnresponsiveness = Offences; type ReportUnresponsiveness = Offences;
type DisabledValidators = Session;
type ExposureListener = StakingExposureListener<Runtime>;
type MaxAuthorities = MaxAuthorities; type MaxAuthorities = MaxAuthorities;
type ApplauseThreshold = ApplauseThreshold; type ApplauseThreshold = ApplauseThreshold;
type OffenceThreshold = OffenceThreshold;
type UnsignedPriority = SlowClapUnsignedPriority; type UnsignedPriority = SlowClapUnsignedPriority;
type HistoryDepth = SlowClapHistoryDepth; type HistoryDepth = SlowClapHistoryDepth;
type MinAuthoritiesNumber = MinAuthoritiesNumber;
type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>; type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>;
} }

View File

@ -191,6 +191,18 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
} }
/// Storage: `GhostNetworks::Networks` (r:1 w:1) /// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_avg_block_speed() -> Weight {
// Proof Size summary in bytes:
// Measured: `302`
// Estimated: `3767`
// Minimum execution time: 49_579_000 picoseconds.
Weight::from_parts(51_126_000, 0)
.saturating_add(Weight::from_parts(0, 3767))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight { fn remove_network() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `302` // Measured: `302`

View File

@ -76,34 +76,7 @@ impl<T: frame_system::Config> ghost_slow_clap::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(7)) .saturating_add(T::DbWeight::get().writes(7))
} }
/// Storage: `GhostSlowClaps::Authorities` (r:2 w:0) fn commit_block()-> Weight {
/// Proof: `GhostSlowClaps::Authorities` (`max_values`: None, `max_size`: None, mode: `Measured`) Default::default()
/// Storage: `GhostSlowClaps::ReceivedClaps` (r:2 w:0)
/// Proof: `GhostSlowClaps::ReceivedClaps` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ClapsInSession` (r:1 w:0)
/// Proof: `GhostSlowClaps::ClapsInSession` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostSlowClaps::ApplausesForTransaction` (r:1 w:1)
/// Proof: `GhostSlowClaps::ApplausesForTransaction` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NullifyNeeded` (r:1 w:0)
/// Proof: `GhostNetworks::NullifyNeeded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmount` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmount` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::BridgedImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::BridgedImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::AccumulatedCommission` (r:1 w:1)
/// Proof: `GhostNetworks::AccumulatedCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn self_applause() -> Weight {
// Proof Size summary in bytes:
// Measured: `861`
// Estimated: `6801`
// Minimum execution time: 258_510_000 picoseconds.
Weight::from_parts(262_353_000, 0)
.saturating_add(Weight::from_parts(0, 6801))
.saturating_add(T::DbWeight::get().reads(12))
.saturating_add(T::DbWeight::get().writes(5))
} }
} }

View File

@ -205,6 +205,7 @@ fn casper_testnet_evm_networks() -> Vec<(u32, Vec<u8>)> {
finality_delay: 69u64, finality_delay: 69u64,
rate_limit_delay: 5_000u64, rate_limit_delay: 5_000u64,
block_distance: 20u64, block_distance: 20u64,
avg_block_speed: 12_000,
network_type: ghost_networks::NetworkType::Evm, network_type: ghost_networks::NetworkType::Evm,
gatekeeper: "0xc85129A097773B7F8970a7364c928C05f265E6A1".into(), gatekeeper: "0xc85129A097773B7F8970a7364c928C05f265E6A1".into(),
topic_name: "0x7ab52ec05c331e6257a3d705d6bea6e4c27277351764ad139209e06b203811a6".into(), topic_name: "0x7ab52ec05c331e6257a3d705d6bea6e4c27277351764ad139209e06b203811a6".into(),