2 Commits

Author SHA1 Message Date
Luke Parker
44d0eeeb18 Restore key gen message match from develop
It was modified in response to the handover completion bug, which has now been
resolved.
2024-06-10 19:04:22 -04:00
Luke Parker
5a9ebc8cdc Correct detection of handover completion 2024-06-10 18:34:58 -04:00
3 changed files with 87 additions and 76 deletions

View File

@@ -643,8 +643,9 @@ pub mod pallet {
// Checks if this session has completed the handover from the prior session. // Checks if this session has completed the handover from the prior session.
fn handover_completed(network: NetworkId, session: Session) -> bool { fn handover_completed(network: NetworkId, session: Session) -> bool {
let Some(current_session) = Self::session(network) else { return false }; let Some(current_session) = Self::session(network) else { return false };
// No handover occurs on genesis
if current_session.0 == 0 { // If the session we've been queried about is old, it must have completed its handover
if current_session.0 > session.0 {
return true; return true;
} }
// If the session we've been queried about has yet to start, it can't have completed its // If the session we've been queried about has yet to start, it can't have completed its
@@ -652,19 +653,21 @@ pub mod pallet {
if current_session.0 < session.0 { if current_session.0 < session.0 {
return false; return false;
} }
if current_session.0 == session.0 {
// Handover is automatically complete for Serai as it doesn't have a handover protocol // Handover is automatically complete for Serai as it doesn't have a handover protocol
// If not Serai, check the prior session had its keys cleared, which happens once its if network == NetworkId::Serai {
// retired return true;
return (network == NetworkId::Serai) ||
(!Keys::<T>::contains_key(ValidatorSet {
network,
session: Session(current_session.0 - 1),
}));
} }
// We're currently in a future session, meaning this session definitely performed itself
// handover // The current session must have set keys for its handover to be completed
true if !Keys::<T>::contains_key(ValidatorSet { network, session }) {
return false;
}
// This must be the first session (which has set keys) OR the prior session must have been
// retired (signified by its keys no longer being present)
(session.0 == 0) ||
(!Keys::<T>::contains_key(ValidatorSet { network, session: Session(session.0 - 1) }))
} }
fn new_session() { fn new_session() {
@@ -682,6 +685,8 @@ pub mod pallet {
} }
} }
// TODO: This is called retire_set, yet just starts retiring the set
// Update the nomenclature within this function
pub fn retire_set(set: ValidatorSet) { pub fn retire_set(set: ValidatorSet) {
// If the prior prior set didn't report, emit they're retired now // If the prior prior set didn't report, emit they're retired now
if PendingSlashReport::<T>::get(set.network).is_some() { if PendingSlashReport::<T>::get(set.network).is_some() {

View File

@@ -32,30 +32,31 @@ pub async fn key_gen<C: Ciphersuite>(
let id = KeyGenId { session: set.session, attempt: 0 }; let id = KeyGenId { session: set.session, attempt: 0 };
for (i, processor) in processors.iter_mut().enumerate() { for (i, processor) in processors.iter_mut().enumerate() {
loop { let msg = processor.recv_message().await;
let msg = processor.recv_message().await; match &msg {
match &msg { CoordinatorMessage::KeyGen(messages::key_gen::CoordinatorMessage::GenerateKey {
CoordinatorMessage::KeyGen(messages::key_gen::CoordinatorMessage::GenerateKey { params,
id: this_id, ..
params, }) => {
shares, participant_is.push(params.i());
}) => {
assert_eq!(id, *this_id);
assert_eq!(params.t(), u16::try_from(((coordinators * 2) / 3) + 1).unwrap(),);
assert_eq!(params.n(), u16::try_from(coordinators).unwrap(),);
assert_eq!(*shares, 1);
participant_is.push(params.i());
break;
}
CoordinatorMessage::Substrate(
messages::substrate::CoordinatorMessage::ConfirmKeyPair { .. },
) => {
continue;
}
_ => panic!("unexpected message: {msg:?}"),
} }
_ => panic!("unexpected message: {msg:?}"),
} }
assert_eq!(
msg,
CoordinatorMessage::KeyGen(messages::key_gen::CoordinatorMessage::GenerateKey {
id,
params: ThresholdParams::new(
u16::try_from(((coordinators * 2) / 3) + 1).unwrap(),
u16::try_from(coordinators).unwrap(),
participant_is[i],
)
.unwrap(),
shares: 1,
})
);
processor processor
.send_message(messages::key_gen::ProcessorMessage::Commitments { .send_message(messages::key_gen::ProcessorMessage::Commitments {
id, id,

View File

@@ -83,46 +83,45 @@ async fn deallocate_stake(
publish_tx(serai, &tx).await publish_tx(serai, &tx).await
} }
async fn wait_till_next_epoch(serai: &Serai, current_epoch: u32) -> Session { async fn get_session(serai: &Serai, network: NetworkId) -> Session {
let mut session = Session(current_epoch); serai
while session.0 < current_epoch + 1 { .as_of_latest_finalized_block()
.await
.unwrap()
.validator_sets()
.session(network)
.await
.unwrap()
.unwrap()
}
async fn wait_till_next_epoch(serai: &Serai) -> Session {
let starting_session = get_session(serai, NetworkId::Serai).await;
let mut session = starting_session;
while session == starting_session {
sleep(Duration::from_secs(6)).await; sleep(Duration::from_secs(6)).await;
session = serai session = get_session(serai, NetworkId::Serai).await;
.as_of_latest_finalized_block()
.await
.unwrap()
.validator_sets()
.session(NetworkId::Serai)
.await
.unwrap()
.unwrap();
} }
session session
} }
async fn get_session(serai: &Serai, block: [u8; 32], network: NetworkId) -> Session { async fn most_recent_new_set_event(serai: &Serai, network: NetworkId) -> ValidatorSetsEvent {
serai.as_of(block).validator_sets().session(network).await.unwrap().unwrap()
}
async fn new_set_events(
serai: &Serai,
session: Session,
network: NetworkId,
) -> Vec<ValidatorSetsEvent> {
let mut current_block = serai.latest_finalized_block().await.unwrap(); let mut current_block = serai.latest_finalized_block().await.unwrap();
let mut current_session = get_session(serai, current_block.hash(), network).await; loop {
while current_session == session {
let events = serai.as_of(current_block.hash()).validator_sets().new_set_events().await.unwrap(); let events = serai.as_of(current_block.hash()).validator_sets().new_set_events().await.unwrap();
if !events.is_empty() { for event in events {
return events; match event {
ValidatorSetsEvent::NewSet { set } => {
if set.network == network {
return event;
}
}
_ => panic!("new_set_events gave non-NewSet event: {event:?}"),
}
} }
current_block = serai.block(current_block.header.parent_hash.0).await.unwrap().unwrap(); current_block = serai.block(current_block.header.parent_hash.0).await.unwrap().unwrap();
current_session = get_session(serai, current_block.hash(), network).await;
} }
panic!("can't find the new set events for session: {} ", session.0);
} }
#[tokio::test] #[tokio::test]
@@ -130,33 +129,39 @@ async fn set_rotation_test() {
new_test( new_test(
|mut processors: Vec<Processor>| async move { |mut processors: Vec<Processor>| async move {
// exclude the last processor from keygen since we will add him later // exclude the last processor from keygen since we will add him later
let excluded = processors.pop().unwrap(); let mut excluded = processors.pop().unwrap();
assert_eq!(processors.len(), COORDINATORS); assert_eq!(processors.len(), COORDINATORS);
// genesis keygen
let _ = key_gen::<Secp256k1>(&mut processors, Session(0)).await;
let pair5 = insecure_pair_from_name("Eve"); let pair5 = insecure_pair_from_name("Eve");
let network = NetworkId::Bitcoin; let network = NetworkId::Bitcoin;
let amount = Amount(1_000_000 * 10_u64.pow(8)); let amount = Amount(1_000_000 * 10_u64.pow(8));
let serai = processors[0].serai().await; let serai = processors[0].serai().await;
// add the last participant into validator set for btc network // add the last participant into validator set for btc network
let block = allocate_stake(&serai, network, amount, &pair5, 0).await; allocate_stake(&serai, network, amount, &pair5, 0).await;
// genesis keygen
let _ = key_gen::<Secp256k1>(&mut processors, Session(0)).await;
// Even the excluded processor should receive the key pair confirmation
match excluded.recv_message().await {
CoordinatorMessage::Substrate(
messages::substrate::CoordinatorMessage::ConfirmKeyPair { session, .. },
) => assert_eq!(session, Session(0)),
_ => panic!("excluded got message other than ConfirmKeyPair"),
}
// wait until next session to see the effect on coordinator // wait until next session to see the effect on coordinator
let current_epoch = get_session(&serai, block, NetworkId::Serai).await; wait_till_next_epoch(&serai).await;
let session = wait_till_next_epoch(&serai, current_epoch.0).await;
// verfiy that coordinator received new_set // verfiy that coordinator received new_set
let events = new_set_events(&serai, session, network).await; assert_eq!(
assert!( most_recent_new_set_event(&serai, network).await,
events.contains(&ValidatorSetsEvent::NewSet { set: ValidatorSet { session, network } }) ValidatorSetsEvent::NewSet { set: ValidatorSet { session: Session(1), network } },
); );
// add the last participant & do the keygen // add the last participant & do the keygen
processors.push(excluded); processors.push(excluded);
let _ = key_gen::<Secp256k1>(&mut processors, session).await; let _ = key_gen::<Secp256k1>(&mut processors, Session(1)).await;
}, },
true, true,
) )