diff --git a/crates/client/entropy_metadata.scale b/crates/client/entropy_metadata.scale index c0c5982a0..dd28d7ff4 100644 Binary files a/crates/client/entropy_metadata.scale and b/crates/client/entropy_metadata.scale differ diff --git a/crates/threshold-signature-server/src/validator/api.rs b/crates/threshold-signature-server/src/validator/api.rs index e0586affb..8a4d3cee5 100644 --- a/crates/threshold-signature-server/src/validator/api.rs +++ b/crates/threshold-signature-server/src/validator/api.rs @@ -200,6 +200,7 @@ pub async fn rotate_network_key( // validate from chain let api = get_api(&app_state.configuration.endpoint).await?; let rpc = get_rpc(&app_state.configuration.endpoint).await?; + validate_rotate_network_key(&api, &rpc).await?; let (signer, _) = get_signer_and_x25519_secret(&app_state.kv_store) .await @@ -284,6 +285,29 @@ pub async fn validate_new_reshare( Ok(()) } +/// Validates rotate_network_key +/// Checks the chain that the reshare was completed +pub async fn validate_rotate_network_key( + api: &OnlineClient, + rpc: &LegacyRpcMethods, +) -> Result<(), ValidatorErr> { + let latest_block_number = rpc + .chain_get_header(None) + .await? + .ok_or_else(|| ValidatorErr::OptionUnwrapError("Failed to get block number".to_string()))? + .number; + + let rotate_keyshares_info_query = entropy::storage().staking_extension().rotate_keyshares(); + let rotate_keyshare_block = query_chain(api, rpc, rotate_keyshares_info_query, None) + .await? + .ok_or_else(|| ValidatorErr::ChainFetch("Rotate Keyshare not in progress"))?; + + if latest_block_number > rotate_keyshare_block { + return Err(ValidatorErr::StaleData); + } + + Ok(()) +} /// Confirms that a validator has succefully reshared. pub async fn confirm_key_reshare( api: &OnlineClient, diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index 9b6b9909a..e98821d6a 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -127,11 +127,61 @@ async fn test_reshare() { serialize(&aux_info_before).unwrap(), serialize(&aux_info_after_rotate).unwrap() ); + + // calling twice doesn't do anything + let response = client + .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) + .send() + .await + .unwrap(); + + assert_eq!(response.text().await.unwrap(), "Kv error: Recv Error: channel closed"); + let key_share_and_aux_data_after_rotate_twice = + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await; + let (key_share_after_rotate_twice, aux_info_after_rotate_twice): KeyShareWithAuxInfo = + deserialize(&key_share_and_aux_data_after_rotate_twice).unwrap(); + + // Check key share has not changed + assert_eq!( + serialize(&key_share_after_rotate_twice).unwrap(), + serialize(&key_share_after_rotate).unwrap() + ); + // Check aux info has not changed + assert_eq!( + serialize(&aux_info_after_rotate_twice).unwrap(), + serialize(&aux_info_after_rotate).unwrap() + ); } // TODO #981 - test signing a message with the new keyshare set clean_tests(); } +#[tokio::test] +#[serial] +async fn test_reshare_none_called() { + initialize_test_logger().await; + clean_tests(); + + let _cxt = test_node_process_testing_state(true).await; + + let add_parent_key_to_kvdb = true; + let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key_to_kvdb).await; + + let validator_ports = vec![3001, 3002, 3003]; + + let client = reqwest::Client::new(); + + for i in 0..validator_ports.len() { + let response = client + .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) + .send() + .await + .unwrap(); + + assert_eq!(response.text().await.unwrap(), "Chain Fetch: Rotate Keyshare not in progress"); + } +} + #[tokio::test] #[serial] async fn test_reshare_validation_fail() { diff --git a/pallets/propagation/src/lib.rs b/pallets/propagation/src/lib.rs index 21f0306b0..7d110665a 100644 --- a/pallets/propagation/src/lib.rs +++ b/pallets/propagation/src/lib.rs @@ -72,13 +72,12 @@ pub mod pallet { let _ = Self::post_user_registration(block_number); let _ = Self::post_attestation_request(block_number); let _ = Self::post_proactive_refresh(block_number); - let _ = Self::post_rotate_keyshare + let _ = Self::post_rotate_keyshare(block_number); } fn on_initialize(block_number: BlockNumberFor) -> Weight { pallet_registry::Dkg::::remove(block_number.saturating_sub(2u32.into())); pallet_staking_extension::ProactiveRefresh::::take(); - // delete rotate keyshare trigger ::WeightInfo::on_initialize() } } @@ -328,7 +327,7 @@ pub mod pallet { /// Submits a request to rotate parent network key the threshold servers. pub fn post_rotate_keyshare(block_number: BlockNumberFor) -> Result<(), http::Error> { let rotate_keyshares = pallet_staking_extension::Pallet::::rotate_keyshares(); - if !rotate_keyshares { + if rotate_keyshares != block_number { return Ok(()); } diff --git a/pallets/propagation/src/tests.rs b/pallets/propagation/src/tests.rs index 857f2b705..eae4e59a3 100644 --- a/pallets/propagation/src/tests.rs +++ b/pallets/propagation/src/tests.rs @@ -146,7 +146,7 @@ fn knows_how_to_mock_several_http_calls() { // now triggers Propagation::post_reshare(7).unwrap(); - pallet_staking_extension::RotateKeyshares::::put(true); + pallet_staking_extension::RotateKeyshares::::put(10); Propagation::post_rotate_keyshare(10).unwrap(); }) } diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index c67308f74..b94707d02 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -233,7 +233,7 @@ pub mod pallet { /// Tell Signers to rotate keyshare #[pallet::storage] #[pallet::getter(fn rotate_keyshares)] - pub type RotateKeyshares = StorageValue<_, bool, ValueQuery>; + pub type RotateKeyshares = StorageValue<_, BlockNumberFor, ValueQuery>; /// A type used to simplify the genesis configuration definition. pub type ThresholdServersConfig = ( @@ -510,7 +510,9 @@ pub mod pallet { let current_signer_length = signers_info.next_signers.len(); if signers_info.confirmations.len() == (current_signer_length - 1) { Signers::::put(signers_info.next_signers.clone()); - RotateKeyshares::::put(true); + RotateKeyshares::::put( + >::block_number() + sp_runtime::traits::One::one(), + ); Self::deposit_event(Event::SignersRotation(signers_info.next_signers)); Ok(Pays::No.into()) } else {