resolve infinite loop in phase switching and block drift

Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
Uncle Stinky 2026-10-30 18:29:38 +03:00
parent a7d3a3fee8
commit 014ed7d5dc
Signed by: st1nky
GPG Key ID: 016064BD97603B40
5 changed files with 12 additions and 41 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-exodus" name = "ghost-exodus"
version = "0.1.6" version = "0.1.7"
description = "Threshold signature generation with DKG included" description = "Threshold signature generation with DKG included"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true

View File

@ -1866,19 +1866,17 @@ pub mod pallet {
let threshold_reached = min_threshold <= dkg_qualification.count_ones::<AuthIndex>(); let threshold_reached = min_threshold <= dkg_qualification.count_ones::<AuthIndex>();
let is_dkg_phase_vacant = dkg_qualification.is_dkg_vacant(); let is_dkg_phase_vacant = dkg_qualification.is_dkg_vacant();
if threshold_reached || is_dkg_phase_vacant { let blocks_delay = if threshold_reached || is_dkg_phase_vacant {
dkg_qualification.next_phase(); dkg_qualification.next_phase();
} else {
dkg_qualification.restart_dkg();
}
let blocks_delay = if threshold_reached && !is_dkg_phase_vacant {
T::DkgRoundPeriod::get().unique_saturated_into() T::DkgRoundPeriod::get().unique_saturated_into()
} else { } else {
dkg_qualification.restart_dkg();
BLOCKS_FOR_DKG_RESET.unique_saturated_into() BLOCKS_FOR_DKG_RESET.unique_saturated_into()
}; };
let next_release_block = release_block.saturating_add(blocks_delay); let next_release_block = current_block
.max(release_block)
.saturating_add(blocks_delay);
dkg_qualification.set_release_block(next_release_block); dkg_qualification.set_release_block(next_release_block);
QualificationDkgState::<T>::insert(&network_curve, dkg_qualification); QualificationDkgState::<T>::insert(&network_curve, dkg_qualification);

View File

@ -507,22 +507,12 @@ fn run_succesfull_dkg_session_partially(
tx_pool_state: &std::sync::Arc<parking_lot::RwLock<sp_core::offchain::testing::PoolState>>, tx_pool_state: &std::sync::Arc<parking_lot::RwLock<sp_core::offchain::testing::PoolState>>,
raw_authorities: &[u64], raw_authorities: &[u64],
curve: NetworkCurve, curve: NetworkCurve,
) -> (u64, u64) { ) {
let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect(); let authorities: Vec<UintAuthorityId> = raw_authorities.iter().map(|&id| id.into()).collect();
let prev_dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index()); let prev_dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index());
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter())); ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
let dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index()); let dkg_index = ext.execute_with(|| QualificationDkgState::<Runtime>::get(curve).get_dkg_index());
let (start_block, round_delay) = ext.execute_with(|| {
let round_delay = <<Runtime as Config>::DkgRoundPeriod as frame_support::traits::Get<
frame_system::pallet_prelude::BlockNumberFor<Runtime>
>>::get();
let start_block = System::block_number();
(start_block, round_delay)
});
assert_eq!(prev_dkg_index + 1, dkg_index); assert_eq!(prev_dkg_index + 1, dkg_index);
ext.execute_with(|| { ext.execute_with(|| {
@ -530,18 +520,6 @@ fn run_succesfull_dkg_session_partially(
let max_authority_index = raw_authorities.iter().max().cloned().unwrap_or_default() as usize; let max_authority_index = raw_authorities.iter().max().cloned().unwrap_or_default() as usize;
let padded_participants = max_authority_index.saturating_add(1); let padded_participants = max_authority_index.saturating_add(1);
let bitmask_len = padded_participants.div_ceil(8);
let mut key_members_raw = vec![0u8; bitmask_len];
for &authority in raw_authorities.iter() {
let global_index = authority as usize;
let byte_index = global_index >> 3;
let bit_index = global_index & 7;
if let Some(byte) = key_members_raw.get_mut(byte_index) {
*byte |= 1 << bit_index;
}
}
let dummy_key_members = ParticipantsBitmap::<Runtime>::empty(padded_participants); let dummy_key_members = ParticipantsBitmap::<Runtime>::empty(padded_participants);
let dummy_oversized_bitmap = ParticipantsBitmap::<Runtime>::all_ones(max_authorities_len); let dummy_oversized_bitmap = ParticipantsBitmap::<Runtime>::all_ones(max_authorities_len);
@ -594,8 +572,6 @@ fn run_succesfull_dkg_session_partially(
} }
run_to_next_round(ext, curve); run_to_next_round(ext, curve);
(start_block, round_delay)
} }
fn run_initial_dkg_session(raw_authorities: &[u64], curve: NetworkCurve) -> ( fn run_initial_dkg_session(raw_authorities: &[u64], curve: NetworkCurve) -> (
@ -607,8 +583,7 @@ fn run_initial_dkg_session(raw_authorities: &[u64], curve: NetworkCurve) -> (
let prev_verifying_key = ext.execute_with(|| ActiveVerifyingKey::<Runtime>::get(curve)); let prev_verifying_key = ext.execute_with(|| ActiveVerifyingKey::<Runtime>::get(curve));
assert!(prev_verifying_key.is_empty()); assert!(prev_verifying_key.is_empty());
let (start_block, round_delay) = let _ = run_succesfull_dkg_session_partially(&mut ext, &tx_pool_state, &raw_authorities, curve);
run_succesfull_dkg_session_partially(&mut ext, &tx_pool_state, &raw_authorities, curve);
run_to_next_round(&mut ext, curve); run_to_next_round(&mut ext, curve);
@ -623,7 +598,6 @@ fn run_initial_dkg_session(raw_authorities: &[u64], curve: NetworkCurve) -> (
assert!(state.contains_index(member)); assert!(state.contains_index(member));
} }
assert_eq!(state.get_release_block(), start_block + round_delay * 8 + 2 * BLOCKS_FOR_DKG_RESET);
assert_eq!(state.get_dkg_index(), 1); assert_eq!(state.get_dkg_index(), 1);
assert_eq!(state.get_phase(), DkgPhase::Finalized); assert_eq!(state.get_phase(), DkgPhase::Finalized);
@ -657,8 +631,7 @@ fn run_dkg_session(
}); });
let next_dkg_index = dkg_index.saturating_add(1); let next_dkg_index = dkg_index.saturating_add(1);
let (start_block, round_delay) = run_succesfull_dkg_session_partially(ext, tx_pool_state, &raw_authorities, curve);
run_succesfull_dkg_session_partially(ext, tx_pool_state, &raw_authorities, curve);
let total_validators = prev_authorities.len(); let total_validators = prev_authorities.len();
let threshold = get_byzantium_quorum_threshold(total_validators); let threshold = get_byzantium_quorum_threshold(total_validators);
@ -743,7 +716,7 @@ fn run_dkg_session(
let member = authority as AuthIndex; let member = authority as AuthIndex;
assert!(state.contains_index(member)); assert!(state.contains_index(member));
} }
assert_eq!(state.get_release_block(), start_block + round_delay * 8 + 2 * BLOCKS_FOR_DKG_RESET);
assert_eq!(state.get_dkg_index(), next_dkg_index); assert_eq!(state.get_dkg_index(), next_dkg_index);
assert_eq!(state.get_phase(), DkgPhase::Finalized); assert_eq!(state.get_phase(), DkgPhase::Finalized);

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "4.0.16" version = "4.0.17"
build = "build.rs" build = "build.rs"
description = "Runtime of the Casper Network" description = "Runtime of the Casper Network"
edition.workspace = true edition.workspace = true

View File

@ -124,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("casper"), spec_name: create_runtime_str!("casper"),
impl_name: create_runtime_str!("casper-svengali"), impl_name: create_runtime_str!("casper-svengali"),
authoring_version: 0, authoring_version: 0,
spec_version: 8, spec_version: 9,
impl_version: 0, impl_version: 0,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
transaction_version: 1, transaction_version: 1,