fix GJKR arbitration, avoid invalid kicks, and synchronize round 5 output

Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
Uncle Stretch 2026-10-10 15:48:50 +03:00
parent d488bf9a43
commit 1dc61fb17d
Signed by: str3tch
GPG Key ID: 84F3190747EE79AA
6 changed files with 246 additions and 64 deletions

View File

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

View File

@ -344,12 +344,17 @@ mod benchmarks {
let dummy_merkle_root = ExodusHash::repeat_byte(69);
let dummy_verifying_key = vec![69u8; network_curve.element_bytes_len()];
let dummy_key_members = vec![15];
let round5_package = PackageContext::default()
.with_network_curve(NetworkCurve::Secp256k1)
.with_authority_index(authority_index)
.with_dkg_index(dkg_index)
.with_dkg_round5(dummy_verifying_key.clone(), dummy_merkle_root)
.with_dkg_round5(
dummy_verifying_key.clone(),
dummy_key_members.clone(),
dummy_merkle_root,
)
.expect("Round5 package should be valid");
let dkg_package = DkgPackage::Round5(round5_package);
@ -366,7 +371,11 @@ mod benchmarks {
dummy_verifying_key,
).expect("Bounded verifying key should be correct");
let metadata_hashes = [dummy_merkle_root.as_ref(), bounded_verifying_key.as_ref()];
let metadata_hashes = [
dummy_merkle_root.as_ref(),
bounded_verifying_key.as_ref(),
dummy_key_members.as_ref(),
];
let verifying_hash = cumulative_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
let verification_key = (network_curve, dkg_index, verifying_hash);
@ -374,10 +383,11 @@ mod benchmarks {
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);
assert!(consensus.state.participants.contains(authority_index));
assert_eq!(consensus.state.participants.count_ones::<AuthIndex>(), 1);
assert_eq!(consensus.state.merkle_root, dummy_merkle_root);
assert_eq!(consensus.state.element_bytes, bounded_verifying_key);
assert_eq!(consensus.members.as_ref(), dummy_key_members);
Ok(())
}
@ -444,8 +454,8 @@ mod benchmarks {
});
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |consensus| {
consensus.participants.insert(authority_index);
consensus.merkle_root = dummy_merkle_root;
consensus.state.participants.insert(authority_index);
consensus.state.merkle_root = dummy_merkle_root;
});
let round6_package = PackageContext::default()

View File

@ -411,7 +411,7 @@ pub mod pallet {
type MaxAuthorities: Get<u32>;
#[pallet::constant]
type MaxAuthoritiesChunks: Get<u32>;
type MaxAuthoritiesChunks: Get<u32> + core::fmt::Debug;
#[pallet::constant]
type DkgRoundPeriod: Get<u64>;
@ -499,6 +499,7 @@ pub mod pallet {
BridgeOverflow,
TooManyPackages,
WrongNetworkType,
MemberNotQualified,
InvalidMerkleProof,
NetworkDoesNotExist,
NoActiveAuthorities,
@ -730,7 +731,10 @@ pub mod pallet {
_,
Twox64Concat, NetworkCurve,
Twox64Concat, DkgIndex,
ConsensusState<ParticipantsBitmap<T>>,
QualifiedConsensusState<
ParticipantsBitmap<T>,
BoundedVec<u8, MaxAuthoritiesBitmaskSize<T>>
>,
ValueQuery,
>;
@ -1230,12 +1234,16 @@ pub mod pallet {
return Err(Error::<T>::Round5PackageInvalidProof.into());
};
let metadata_hashes = [round5.merkle_root.as_ref(), round5.verifying_key.as_ref()];
let verifying_hash = cumulative_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
let state = QualificationDkgState::<T>::get(&network_curve);
ensure!(state.is_fifth_phase(), Error::<T>::DkgWrongRound);
let metadata_hashes = [
round5.merkle_root.as_ref(),
round5.verifying_key.as_ref(),
round5.key_members.as_ref(),
];
let verifying_hash = cumulative_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
let dkg_index = state.get_dkg_index();
let verification_key = (network_curve, dkg_index, verifying_hash);
@ -1257,15 +1265,16 @@ pub mod pallet {
Ok(bitmap.clone())
})?;
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |state| {
let state_participants_count = state.participants.count_ones::<AuthIndex>();
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |current| {
let state_participants_count = current.state.participants.count_ones::<AuthIndex>();
let latest_participants_count = latest_participants.count_ones::<AuthIndex>();
if state_participants_count < latest_participants_count {
*state = ConsensusState::new(
*current = QualifiedConsensusState::new(
round5.verifying_key,
latest_participants,
round5.merkle_root,
round5.key_members,
);
}
});
@ -1314,12 +1323,12 @@ pub mod pallet {
ensure!(state.is_sixth_phase(), Error::<T>::DkgWrongRound);
let dkg_index = state.get_dkg_index();
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, &dkg_index);
let qualified_consensus = VerifyingKeyConsensus::<T>::get(&network_curve, &dkg_index);
network_curve.verify_merkle_proof(
&round6.verifying_share,
&round6.merkle_proof,
consensus.merkle_root,
qualified_consensus.state.merkle_root,
authority_index,
).map_err(|_| Error::<T>::InvalidMerkleProof)?;
@ -2513,10 +2522,13 @@ impl<T: Config> Pallet<T> {
},
|weight| {
weight.saturating_accrue(T::DbWeight::get().reads(1));
let state = VerifyingKeyConsensus::<T>::get(&network_curve, &dkg_index);
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, &dkg_index);
if state.participants.count_ones::<AuthIndex>() < min_threshold {
if consensus.state.participants.count_ones::<AuthIndex>() < min_threshold {
dkg_qualification.nullify_indexes();
} else {
let key_members = ParticipantsBitmap::<T>::from_bitmask(&consensus.members);
dkg_qualification.intersect_indexes(&key_members);
}
})
}
@ -2548,7 +2560,7 @@ impl<T: Config> Pallet<T> {
weight.saturating_accrue(T::DbWeight::get().reads(1));
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, &dkg_index);
let verifying_key_slice = consensus.element_bytes.as_slice();
let verifying_key_slice = consensus.state.element_bytes.as_slice();
if verifying_key_slice.len() != network_curve.element_bytes_len() {
dkg_qualification.nullify_indexes();
@ -2587,7 +2599,7 @@ impl<T: Config> Pallet<T> {
CurrentExodus::<T>::put(exodus_session);
weight.saturating_accrue(T::DbWeight::get().writes(1));
dkg_qualification.set_verifying_key(consensus.element_bytes);
dkg_qualification.set_verifying_key(consensus.state.element_bytes);
})
}
@ -2979,6 +2991,10 @@ impl<T: Config> Pallet<T> {
dkg_package: &DkgPackage<NetworkCurve, T>,
signature: &<T::AuthorityId as RuntimeAppPublic>::Signature,
) -> Result<(), InvalidTransaction> {
let DkgPackage::Round5(round5) = dkg_package else {
return Err(InvalidTransaction::BadProof);
};
let network_curve = dkg_package.get_network_curve();
let authority_index = dkg_package.get_authority_index();
let package_dkg_index = dkg_package.get_dkg_index();
@ -3009,6 +3025,22 @@ impl<T: Config> Pallet<T> {
return Err(InvalidTransaction::BadProof);
}
let has_non_qualified_member = round5.key_members
.iter()
.enumerate()
.any(|(byte_idx, &byte)| {
if byte == 0 { return false; }
(0..8).any(|bit_idx| {
if (byte & (1u8 << bit_idx)) == 0 { return false; }
let global_index = byte_idx * 8 + bit_idx;
!state.contains_index(global_index)
})
});
if has_non_qualified_member {
return Err(InvalidTransaction::BadProof);
}
let authority = QualificationAuthorities::<T>::get(&network_curve)
.get(authority_index as usize)
.cloned()
@ -4328,7 +4360,7 @@ impl<T: Config> Pallet<T> {
let verification_found_for_self =
VerifyingKeyConsensus::<T>::iter_values()
.any(|state| state.participants.contains(authority_index));
.any(|consensus| consensus.state.participants.contains(authority_index));
if verification_found_for_self {
return Ok(ExodusOk::DkgRoundAlreadyPassed(
@ -4415,6 +4447,30 @@ impl<T: Config> Pallet<T> {
DkgStorageEnum::Round5 { secret_share, merkle_proof }
)?;
let padded_participants = qualification_state
.highest_bit::<usize>()
.map(|bit_pos| bit_pos.saturating_add(1))
.unwrap_or_default();
let bitmask_len = padded_participants.div_ceil(8);
let mut key_members_bitmask = vec![0u8; bitmask_len];
for &member_index in round1_packages.keys() {
let global_index = member_index as usize;
let byte_index = global_index >> 3usize;
let bit_index = global_index & 7usize;
if let Some(byte) = key_members_bitmask.get_mut(byte_index) {
*byte |= 1u8 << bit_index;
}
}
let self_global_index = authority_index as usize;
if let Some(byte) = key_members_bitmask.get_mut(self_global_index >> 3) {
*byte |= 1 << (self_global_index & 7);
}
let current_dkg_index = QualificationDkgState::<T>::get(&network_curve)
.get_dkg_index();
@ -4423,7 +4479,11 @@ impl<T: Config> Pallet<T> {
current_dkg_index,
&mut round_metadata,
|context| {
let package = context.with_dkg_round5(verifying_key, merkle_root)?;
let package = context.with_dkg_round5(
verifying_key,
key_members_bitmask,
merkle_root,
)?;
Ok(DkgPackage::Round5(package))
},
|dkg_package, signature| {
@ -4573,32 +4633,40 @@ impl<T: Config> Pallet<T> {
let round2_package_size = blob_len.saturating_div(padded_participants);
for (&accuser_index, accused_bitmap) in Complaints::<T>::get(network_curve).iter() {
if !qualification_state.contains_index(accuser_index) { continue; }
if accuser_index == authority_index { continue; }
let raw_round2_packages: BTreeMap<AuthIndex, Vec<u8>> =
Self::gather_incoming_offchain_packages(
network_curve,
accuser_index,
ROUND_NUMBER_4,
&accused_bitmap,
round2_package_size,
|mut raw_slice| Vec::<u8>::decode(&mut raw_slice).ok(),
);
let mut kicked = sp_std::collections::btree_set::BTreeSet::new();
let mut all_justifications = sp_std::collections::btree_map::BTreeMap::new();
for (&accuser_index, accused_bitmap) in Complaints::<T>::get(network_curve).iter() {
if !qualification_state.contains_index(accuser_index) {
round1_packages.remove(&accuser_index);
round2_packages.remove(&accuser_index);
continue;
}
for accused_index in accused_bitmap.iter::<AuthIndex>() {
if !qualification_state.contains_index(accused_index) { continue; }
if kicked.contains(&accused_index) { continue; }
if accused_index == authority_index { continue; }
let justifications = all_justifications.entry(accused_index)
.or_insert_with(|| {
let key = Self::create_offchain_dkg_key(network_curve, accused_index, ROUND_NUMBER_4);
StorageValueRef::persistent(&key).get::<BundledPackages>().ok().flatten()
});
let maybe_justification = justifications.as_ref().and_then(|bundle| {
Self::locate_package_bounds(bundle, round2_package_size, accuser_index)
.and_then(|(start, end)| {
bundle.blob.get(start..end).and_then(|raw_slice| {
Vec::<u8>::decode(&mut &raw_slice[..]).ok()
})
})
});
let maybe_round1_package = round1_packages.get(&accused_index);
let maybe_round2_package = raw_round2_packages.get(&accused_index);
let (round1_package, round2_package) =
match (maybe_round1_package, maybe_round2_package) {
match (maybe_round1_package, maybe_justification) {
(Some(round1_package), Some(round2_package)) => {
(round1_package, round2_package)
},
@ -4613,13 +4681,13 @@ impl<T: Config> Pallet<T> {
match network_curve.dkg_verify_private_package(
accuser_index,
round1_package,
round2_package,
&round2_package,
) {
Ok(_) => {
if accuser_index != authority_index { continue; }
round2_packages.insert(
accused_index,
round2_package.clone(),
round2_package,
);
},
Err(_) => {

View File

@ -603,7 +603,27 @@ fn run_succesfull_dkg_session_partially(
assert_eq!(prev_dkg_index + 1, dkg_index);
ext.execute_with(|| {
let dummy_oversized_bitmap = ParticipantsBitmap::<Runtime>::all_ones(1337);
let max_authorities_len = raw_authorities.len();
let max_authority_index = raw_authorities.iter().max().cloned().unwrap_or_default() as usize;
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: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<Runtime>> =
key_members_raw.try_into().unwrap();
let dummy_oversized_bitmap = ParticipantsBitmap::<Runtime>::all_ones(max_authorities_len);
let mut map: BitmapByAuthority<Runtime> = Default::default();
for authority in raw_authorities.iter() {
@ -625,10 +645,11 @@ fn run_succesfull_dkg_session_partially(
vec![69u8; ELEMENT_MAX_BYTES as usize],
).unwrap();
let dummy_consensus_state = ConsensusState::new(
let dummy_consensus_state = QualifiedConsensusState::new(
dummy_verifying_key,
dummy_oversized_bitmap,
DUMMY_HASH,
dummy_key_members,
);
VerifyingKeyConsensus::<Runtime>::insert(curve, prev_dkg_index, dummy_consensus_state);
@ -1021,6 +1042,56 @@ fn run_dkg_session(
assert_ne!(prev_active_authorities, active_authorities);
}
#[test]
fn test_exodus_dkg_distributed_synced_exclusion() {
let (mut ext, tx_pool_state) = new_test_ext();
let curve = NetworkCurve::Secp256k1;
let honest_validators = vec![0, 1, 2, 4, 5, 6, 7, 8, 9];
let malicious_validator = 3;
let all_validators = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let authorities: Vec<UintAuthorityId> = all_validators.iter().map(|&id| id.into()).collect();
ext.execute_with(|| Exodus::start_dkg_qualification(authorities, NetworkCurve::iter()));
run_to_next_round(&mut ext, curve);
for &authority in &all_validators {
assert_ok!(execute_round0_happy_path(&mut ext, &tx_pool_state, curve, authority));
}
run_to_next_round(&mut ext, curve);
for &authority in &all_validators {
assert_ok!(execute_round1_happy_path(&mut ext, &tx_pool_state, curve, authority));
}
let remaining_rounds = [
execute_round2_happy_path,
execute_round3_happy_path,
execute_round4_happy_path,
execute_round5_happy_path,
execute_round6_happy_path,
];
for dkg_round in remaining_rounds {
run_to_next_round(&mut ext, curve);
for &authority in &honest_validators {
assert_ok!(dkg_round(&mut ext, &tx_pool_state, curve, authority));
}
}
run_to_next_round(&mut ext, curve);
ext.execute_with(|| {
let state = QualificationDkgState::<Runtime>::get(curve);
assert_eq!(state.get_phase(), DkgPhase::Round7);
assert!(!state.contains_index(malicious_validator));
for &authority in &honest_validators {
assert!(state.contains_index(authority));
}
});
}
#[test]
fn test_all_validators_can_execute_initial_dkg() {
let curve = NetworkCurve::Secp256k1;

View File

@ -6,6 +6,30 @@ use frame_support::{BoundedVec, traits::ConstU32};
use crate::{ExodusHash, ELEMENT_MAX_BYTES};
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct QualifiedConsensusState<Bitmap, Bitmask> {
pub state: ConsensusState<Bitmap>,
pub members: Bitmask,
}
impl<Bitmap, Bitmask> QualifiedConsensusState<Bitmap, Bitmask> {
pub fn new(
element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
participants: Bitmap,
merkle_root: ExodusHash,
members: Bitmask,
) -> Self {
Self {
members,
state: ConsensusState::new(
element_bytes,
participants,
merkle_root,
)
}
}
}
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct ConsensusState<Bitmap> {
pub element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,

View File

@ -75,7 +75,7 @@ where
Round2(Round2Package<NetworkCurve, T>),
Round3(Round3Package<NetworkCurve, T>),
Round4(Round4Package<NetworkCurve, T>),
Round5(Round5Package<NetworkCurve>),
Round5(Round5Package<NetworkCurve, T>),
Round6(Round6Package<NetworkCurve, T>),
}
@ -101,7 +101,7 @@ where
}
}
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct PackageContext<NetworkCurve> {
authority_index: AuthIndex,
network_curve: NetworkCurve,
@ -140,13 +140,13 @@ where
}
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct BundledPackages {
pub blob: Vec<u8>,
pub bitmask: Vec<u8>,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct EncryptionBundledPackages<T>
where
@ -180,7 +180,7 @@ impl<T: crate::pallet::Config> TryFrom<BundledPackages> for EncryptionBundledPac
}
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct JustificationsBundledPackages<T>
where
@ -214,7 +214,7 @@ impl<T: crate::pallet::Config> TryFrom<BundledPackages> for JustificationsBundle
}
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct ExodusNonceCommitment<NetworkCurve> {
context: PackageContext<NetworkCurve>,
@ -223,7 +223,7 @@ pub struct ExodusNonceCommitment<NetworkCurve> {
pub session: ExodusSession,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct ExodusGroupCommitment<NetworkCurve> {
context: PackageContext<NetworkCurve>,
pub group_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
@ -231,7 +231,7 @@ pub struct ExodusGroupCommitment<NetworkCurve> {
pub session: ExodusSession,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct ExodusSignatureShare<NetworkCurve, T>
where
@ -244,13 +244,13 @@ where
pub session: ExodusSession,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct Round0Package<NetworkCurve> {
context: PackageContext<NetworkCurve>,
pub package_hash: ExodusHash,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round1Package<NetworkCurve, T>
where
@ -260,7 +260,7 @@ where
pub package: BoundedVec<u8, crate::Round1MaxBytes<T>>,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round2Package<NetworkCurve, T>
where
@ -270,7 +270,7 @@ where
pub bundle: EncryptionBundledPackages<T>,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round3Package<NetworkCurve, T>
where
@ -280,7 +280,7 @@ where
pub indices: BoundedVec<u8, crate::AccusedIndicesMaxBytes<T>>,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round4Package<NetworkCurve, T>
where
@ -290,14 +290,19 @@ where
pub bundle: JustificationsBundledPackages<T>,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub struct Round5Package<NetworkCurve> {
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round5Package<NetworkCurve, T>
where
T: crate::pallet::Config,
{
context: PackageContext<NetworkCurve>,
pub key_members: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<T>>,
pub verifying_key: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
pub merkle_root: ExodusHash,
}
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Round6Package<NetworkCurve, T>
where
@ -417,16 +422,20 @@ impl<NetworkCurve> PackageContext<NetworkCurve> {
Ok(Round4Package { context: self, bundle })
}
pub fn with_dkg_round5(
pub fn with_dkg_round5<T: crate::pallet::Config>(
self,
verifying_key_vec: Vec<u8>,
key_members_vec: Vec<u8>,
merkle_root: ExodusHash,
) -> Result<Round5Package<NetworkCurve>, ExodusError> {
) -> Result<Round5Package<NetworkCurve, T>, ExodusError> {
let key_members = BoundedVec::<u8, crate::MaxAuthoritiesBitmaskSize<T>>::try_from(key_members_vec)
.map_err(|_| ExodusError::DeserializationError)?;
let verifying_key =
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(verifying_key_vec)
.map_err(|_| ExodusError::DeserializationError)?;
Ok(Round5Package { context: self, verifying_key, merkle_root })
Ok(Round5Package { context: self, key_members, verifying_key, merkle_root })
}
pub fn with_dkg_round6<T: crate::pallet::Config>(