From 1c36ae0b94592c78bed14b5c7db2c0571b05cc78 Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 16 Dec 2024 14:11:20 +0100 Subject: [PATCH] Allow for entropy-tss to be put in a non-ready state --- .../protocol/src/protocol_transport/errors.rs | 2 ++ crates/threshold-signature-server/src/lib.rs | 15 +++++++++++++ crates/threshold-signature-server/src/main.rs | 22 ++++++++++++------- .../src/node_info/api.rs | 2 ++ .../src/signing_client/api.rs | 4 ++++ .../src/signing_client/errors.rs | 2 ++ .../src/signing_client/protocol_transport.rs | 4 ++++ .../src/user/api.rs | 11 ++++++++++ .../src/user/errors.rs | 2 ++ .../src/validator/api.rs | 8 +++++++ .../src/validator/errors.rs | 2 ++ 11 files changed, 66 insertions(+), 8 deletions(-) diff --git a/crates/protocol/src/protocol_transport/errors.rs b/crates/protocol/src/protocol_transport/errors.rs index b22f7d93b..cc4186fc8 100644 --- a/crates/protocol/src/protocol_transport/errors.rs +++ b/crates/protocol/src/protocol_transport/errors.rs @@ -40,6 +40,8 @@ pub enum WsError { Serialization(#[from] bincode::Error), #[error("Received bad subscribe message")] BadSubscribeMessage, + #[error("Node has started fresh and not yet successfully set up")] + NotReady, } /// An error relating to handling a `ProtocolMessage` diff --git a/crates/threshold-signature-server/src/lib.rs b/crates/threshold-signature-server/src/lib.rs index 2063512d4..d70c2419f 100644 --- a/crates/threshold-signature-server/src/lib.rs +++ b/crates/threshold-signature-server/src/lib.rs @@ -178,6 +178,7 @@ use axum::{ use entropy_kvdb::kv_manager::KvManager; use rand_core::OsRng; use sp_core::{crypto::AccountId32, sr25519, Pair}; +use std::sync::{Arc, RwLock}; use subxt::{tx::PairSigner, utils::AccountId32 as SubxtAccountId32}; use tower_http::{ cors::{Any, CorsLayer}, @@ -201,6 +202,7 @@ use crate::{ #[derive(Clone)] pub struct AppState { + ready: Arc>, listener_state: ListenerState, pair: sr25519::Pair, x25519_secret: StaticSecret, @@ -223,6 +225,7 @@ impl AppState { }; Self { + ready: Arc::new(RwLock::new(false)), pair, x25519_secret, listener_state: ListenerState::default(), @@ -231,6 +234,18 @@ impl AppState { } } + pub fn is_ready(&self) -> bool { + match self.ready.read() { + Ok(r) => *r, + _ => false, + } + } + + pub fn make_ready(&self) { + let mut is_ready = self.ready.write().unwrap(); + *is_ready = true; + } + /// Get a [PairSigner] for submitting extrinsics with subxt pub fn signer(&self) -> PairSigner { PairSigner::::new(self.pair.clone()) diff --git a/crates/threshold-signature-server/src/main.rs b/crates/threshold-signature-server/src/main.rs index bd9451e02..bfcd6b4c8 100644 --- a/crates/threshold-signature-server/src/main.rs +++ b/crates/threshold-signature-server/src/main.rs @@ -62,15 +62,21 @@ async fn main() { setup_latest_block_number(&kv_store).await.expect("Issue setting up Latest Block Number"); - // Below deals with syncing the kvdb - let addr = SocketAddr::from_str(&args.threshold_url).expect("failed to parse threshold url."); - - entropy_tss::launch::check_node_prerequisites( - &app_state.configuration.endpoint, - &app_state.account_id().to_ss58check(), - ) - .await; + { + let app_state = app_state.clone(); + tokio::spawn(async move { + // Check for a connection to the chain node parallel to starting the tss_server so that + // we already can expose the `/info` http route + entropy_tss::launch::check_node_prerequisites( + &app_state.configuration.endpoint, + &app_state.account_id().to_ss58check(), + ) + .await; + app_state.make_ready(); + }); + } + let addr = SocketAddr::from_str(&args.threshold_url).expect("failed to parse threshold url."); let listener = tokio::net::TcpListener::bind(&addr) .await .expect("Unable to bind to given server address."); diff --git a/crates/threshold-signature-server/src/node_info/api.rs b/crates/threshold-signature-server/src/node_info/api.rs index 48fab750f..066199975 100644 --- a/crates/threshold-signature-server/src/node_info/api.rs +++ b/crates/threshold-signature-server/src/node_info/api.rs @@ -35,6 +35,7 @@ pub async fn hashes() -> Json> { /// Public signing and encryption keys associated with a TS server #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] pub struct TssPublicKeys { + pub connected_to_chain: bool, pub tss_account: AccountId32, pub x25519_public_key: X25519PublicKey, } @@ -43,6 +44,7 @@ pub struct TssPublicKeys { #[tracing::instrument(skip_all)] pub async fn info(State(app_state): State) -> Result, GetInfoError> { Ok(Json(TssPublicKeys { + connected_to_chain: app_state.is_ready(), x25519_public_key: app_state.x25519_public_key(), tss_account: app_state.subxt_account_id(), })) diff --git a/crates/threshold-signature-server/src/signing_client/api.rs b/crates/threshold-signature-server/src/signing_client/api.rs index b6a507e2d..a496f127f 100644 --- a/crates/threshold-signature-server/src/signing_client/api.rs +++ b/crates/threshold-signature-server/src/signing_client/api.rs @@ -78,6 +78,10 @@ pub async fn proactive_refresh( State(app_state): State, encoded_data: Bytes, ) -> Result { + if !app_state.is_ready() { + return Err(ProtocolErr::NotReady); + } + let ocw_data = OcwMessageProactiveRefresh::decode(&mut encoded_data.as_ref())?; let api = get_api(&app_state.configuration.endpoint).await?; let rpc = get_rpc(&app_state.configuration.endpoint).await?; diff --git a/crates/threshold-signature-server/src/signing_client/errors.rs b/crates/threshold-signature-server/src/signing_client/errors.rs index 4079c0162..0cf1ec0cc 100644 --- a/crates/threshold-signature-server/src/signing_client/errors.rs +++ b/crates/threshold-signature-server/src/signing_client/errors.rs @@ -110,6 +110,8 @@ pub enum ProtocolErr { Listener(#[from] entropy_protocol::errors::ListenerErr), #[error("Failed to derive BIP-32 account: {0}")] Bip32DerivationError(#[from] bip32::Error), + #[error("Node has started fresh and not yet successfully set up")] + NotReady, } impl IntoResponse for ProtocolErr { diff --git a/crates/threshold-signature-server/src/signing_client/protocol_transport.rs b/crates/threshold-signature-server/src/signing_client/protocol_transport.rs index b8234d7b1..5c266753b 100644 --- a/crates/threshold-signature-server/src/signing_client/protocol_transport.rs +++ b/crates/threshold-signature-server/src/signing_client/protocol_transport.rs @@ -113,6 +113,10 @@ pub async fn open_protocol_connections( /// Handle an incoming websocket connection pub async fn handle_socket(socket: WebSocket, app_state: AppState) -> Result<(), WsError> { + if !app_state.is_ready() { + return Err(WsError::NotReady); + } + let (mut encrypted_connection, serialized_signed_message) = noise_handshake_responder(socket, &app_state.x25519_secret) .await diff --git a/crates/threshold-signature-server/src/user/api.rs b/crates/threshold-signature-server/src/user/api.rs index 63eb80fb8..21c6b62bb 100644 --- a/crates/threshold-signature-server/src/user/api.rs +++ b/crates/threshold-signature-server/src/user/api.rs @@ -89,6 +89,9 @@ pub async fn relay_tx( State(app_state): State, Json(encrypted_msg): Json, ) -> Result<(StatusCode, Body), UserErr> { + if !app_state.is_ready() { + return Err(UserErr::NotReady); + } let api = get_api(&app_state.configuration.endpoint).await?; let rpc = get_rpc(&app_state.configuration.endpoint).await?; @@ -217,6 +220,10 @@ pub async fn sign_tx( State(app_state): State, Json(encrypted_msg): Json, ) -> Result<(StatusCode, Body), UserErr> { + if !app_state.is_ready() { + return Err(UserErr::NotReady); + } + let api = get_api(&app_state.configuration.endpoint).await?; let rpc = get_rpc(&app_state.configuration.endpoint).await?; @@ -378,6 +385,10 @@ pub async fn generate_network_key( State(app_state): State, encoded_data: Bytes, ) -> Result { + if !app_state.is_ready() { + return Err(UserErr::NotReady); + } + let data = OcwMessageDkg::decode(&mut encoded_data.as_ref())?; tracing::Span::current().record("block_number", data.block_number); diff --git a/crates/threshold-signature-server/src/user/errors.rs b/crates/threshold-signature-server/src/user/errors.rs index f17942ca8..30cd0dfa9 100644 --- a/crates/threshold-signature-server/src/user/errors.rs +++ b/crates/threshold-signature-server/src/user/errors.rs @@ -179,6 +179,8 @@ pub enum UserErr { TooFewSigners, #[error("Non signer sent from relayer")] IncorrectSigner, + #[error("Node has started fresh and not yet successfully set up")] + NotReady, } impl From for UserErr { diff --git a/crates/threshold-signature-server/src/validator/api.rs b/crates/threshold-signature-server/src/validator/api.rs index 8a82ef7c5..37cee0dc5 100644 --- a/crates/threshold-signature-server/src/validator/api.rs +++ b/crates/threshold-signature-server/src/validator/api.rs @@ -53,6 +53,10 @@ pub async fn new_reshare( State(app_state): State, encoded_data: Bytes, ) -> Result { + if !app_state.is_ready() { + return Err(ValidatorErr::NotReady); + } + let data = OcwMessageReshare::decode(&mut encoded_data.as_ref())?; let api = get_api(&app_state.configuration.endpoint).await?; @@ -204,6 +208,10 @@ async fn do_reshare( pub async fn rotate_network_key( State(app_state): State, ) -> Result { + if !app_state.is_ready() { + return Err(ValidatorErr::NotReady); + } + // validate from chain let api = get_api(&app_state.configuration.endpoint).await?; let rpc = get_rpc(&app_state.configuration.endpoint).await?; diff --git a/crates/threshold-signature-server/src/validator/errors.rs b/crates/threshold-signature-server/src/validator/errors.rs index 7d64816d4..3556139e0 100644 --- a/crates/threshold-signature-server/src/validator/errors.rs +++ b/crates/threshold-signature-server/src/validator/errors.rs @@ -97,6 +97,8 @@ pub enum ValidatorErr { NotImplemented, #[error("Input must be 32 bytes: {0}")] TryFromSlice(#[from] TryFromSliceError), + #[error("Node has started fresh and not yet successfully set up")] + NotReady, } impl IntoResponse for ValidatorErr {