From 160f8a857d4ad2a7f9be50f01c139dc7ede6dc95 Mon Sep 17 00:00:00 2001 From: Jesse Abramowitz Date: Wed, 21 Aug 2024 12:18:24 -0400 Subject: [PATCH] Rotate parent netowrk key takes 2 steps --- crates/shared/src/constants.rs | 3 ++ crates/threshold-signature-server/src/lib.rs | 3 +- .../src/validator/api.rs | 37 ++++++++++++++++--- .../src/validator/tests.rs | 26 ++++++++++++- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/crates/shared/src/constants.rs b/crates/shared/src/constants.rs index 3193ff998..d6a4ee964 100644 --- a/crates/shared/src/constants.rs +++ b/crates/shared/src/constants.rs @@ -61,6 +61,9 @@ pub const DEVICE_KEY_PROXY: &[u8] = include_bytes!("../device_key_proxy.wasm"); /// Network parent key specific size to fit into [u8; 32] to save extra code pub const NETWORK_PARENT_KEY: &str = "NETWORK_PARENT_KEY_FOR_ENTROPY_"; +// Next Network parent key ready to be swapped in to new one +pub const NEXT_NETWORK_PARENT_KEY: &str = "NEXT_NETWORK_PARENT_KEY"; + /// Total signers on the network with the parent key pub const TOTAL_SIGNERS: u8 = 3; diff --git a/crates/threshold-signature-server/src/lib.rs b/crates/threshold-signature-server/src/lib.rs index ff145a3b3..99e52da85 100644 --- a/crates/threshold-signature-server/src/lib.rs +++ b/crates/threshold-signature-server/src/lib.rs @@ -157,7 +157,7 @@ use crate::{ r#unsafe::api::{delete, put, remove_keys, unsafe_get}, signing_client::{api::*, ListenerState}, user::api::*, - validator::api::new_reshare, + validator::api::{new_reshare, rotate_network_key}, }; #[derive(Clone)] @@ -180,6 +180,7 @@ pub fn app(app_state: AppState) -> Router { .route("/user/sign_tx", post(sign_tx)) .route("/signer/proactive_refresh", post(proactive_refresh)) .route("/validator/reshare", post(new_reshare)) + .route("/validator/rotate_network_key", post(rotate_network_key)) .route("/attest", post(attest)) .route("/healthz", get(healthz)) .route("/version", get(get_version)) diff --git a/crates/threshold-signature-server/src/validator/api.rs b/crates/threshold-signature-server/src/validator/api.rs index 810996711..f3e6d0954 100644 --- a/crates/threshold-signature-server/src/validator/api.rs +++ b/crates/threshold-signature-server/src/validator/api.rs @@ -35,7 +35,7 @@ pub use entropy_protocol::{ execute_protocol::{execute_protocol_generic, execute_reshare, Channels, PairWrapper}, KeyParams, KeyShareWithAuxInfo, Listener, PartyId, SessionId, ValidatorInfo, }; -use entropy_shared::{OcwMessageReshare, NETWORK_PARENT_KEY}; +use entropy_shared::{OcwMessageReshare, NETWORK_PARENT_KEY, NEXT_NETWORK_PARENT_KEY}; use parity_scale_codec::{Decode, Encode}; use sp_core::Pair; use std::{collections::BTreeSet, str::FromStr}; @@ -176,13 +176,13 @@ pub async fn new_reshare( let serialized_key_share = key_serialize(&(new_key_share, aux_info)) .map_err(|_| ProtocolErr::KvSerialize("Kv Serialize Error".to_string()))?; - let network_parent_key = hex::encode(NETWORK_PARENT_KEY); - // TODO: should this be a two step process? see # https://github.com/entropyxyz/entropy-core/issues/968 - if app_state.kv_store.kv().exists(&network_parent_key).await? { - app_state.kv_store.kv().delete(&network_parent_key).await? + let next_network_parent_key = hex::encode(NEXT_NETWORK_PARENT_KEY); + + if app_state.kv_store.kv().exists(&next_network_parent_key).await? { + app_state.kv_store.kv().delete(&next_network_parent_key).await? }; - let reservation = app_state.kv_store.kv().reserve_key(network_parent_key).await?; + let reservation = app_state.kv_store.kv().reserve_key(next_network_parent_key).await?; app_state.kv_store.kv().put(reservation, serialized_key_share.clone()).await?; // TODO: Error handling really complex needs to be thought about. @@ -190,6 +190,31 @@ pub async fn new_reshare( Ok(StatusCode::OK) } +// HTTP POST endpoint called by the off-chain worker (propagation pallet) after network reshare. +/// +/// This roatates network key. +#[tracing::instrument(skip_all)] +pub async fn rotate_network_key( + State(app_state): State, +) -> Result { + // validate from chain + + let network_parent_key_heading = hex::encode(NETWORK_PARENT_KEY); + let next_network_parent_key_heading = hex::encode(NEXT_NETWORK_PARENT_KEY); + + let new_parent_key = app_state.kv_store.kv().get(&next_network_parent_key_heading).await?; + + if app_state.kv_store.kv().exists(&network_parent_key_heading).await? { + app_state.kv_store.kv().delete(&network_parent_key_heading).await?; + }; + + app_state.kv_store.kv().delete(&next_network_parent_key_heading).await?; + + let reservation = app_state.kv_store.kv().reserve_key(network_parent_key_heading).await?; + app_state.kv_store.kv().put(reservation, new_parent_key).await?; + Ok(StatusCode::OK) +} + // Validates new reshare endpoint /// Checks the chain for validity of data and block number of data matches current block pub async fn validate_new_reshare( diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index 187c46206..9b6b9909a 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -102,9 +102,31 @@ async fn test_reshare() { deserialize(&key_share_and_aux_data_after).unwrap(); // Check key share has changed - assert_ne!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap()); + assert_eq!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap()); // Check aux info has changed - assert_ne!(serialize(&aux_info_before).unwrap(), serialize(&aux_info_after).unwrap()); + assert_eq!(serialize(&aux_info_before).unwrap(), serialize(&aux_info_after).unwrap()); + + let _ = client + .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) + .send() + .await + .unwrap(); + + let key_share_and_aux_data_after_rotate = + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await; + let (key_share_after_rotate, aux_info_after_rotate): KeyShareWithAuxInfo = + deserialize(&key_share_and_aux_data_after_rotate).unwrap(); + + // Check key share has changed + assert_ne!( + serialize(&key_share_before).unwrap(), + serialize(&key_share_after_rotate).unwrap() + ); + // Check aux info has changed + assert_ne!( + serialize(&aux_info_before).unwrap(), + serialize(&aux_info_after_rotate).unwrap() + ); } // TODO #981 - test signing a message with the new keyshare set clean_tests();