From 099775f6b0439485f5f0978e255e787923f2ac5e Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:39:29 -0700 Subject: [PATCH] Add sort to subgroup signer selection (#900) * add sort to subgroup signer selection * add helper get subgroup endpoint * update comment * add changelog * Apply suggestions from code review Co-authored-by: Hernando Castano * fix * add debug --------- Co-authored-by: Hernando Castano --- CHANGELOG.md | 4 +- crates/client/src/user.rs | 10 ++--- crates/threshold-signature-server/src/lib.rs | 3 +- .../src/node_info/api.rs | 24 +++++++++++- .../src/node_info/tests.rs | 37 ++++++++++++++++++- .../src/user/tests.rs | 2 +- 6 files changed, 70 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9994ddfa7..93c7fa91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,14 @@ At the moment this project **does not** adhere to - In [#881](https://github.com/entropyxyz/entropy-core/pull/881) the `HashingAlgorithm` enum is given an additional variant `Blake2_256` and marked as `non_exhaustive` meaning we must handle the case that an unknown variant is added in the future. + - In [#900](https://github.com/entropyxyz/entropy-core/pull/900) the subgroup signer selection now adds a ```.sort()``` function before selecting the index to ensure consistentcy across libraries languages and clients ### Added - Add a way to change program modification account ([#843](https://github.com/entropyxyz/entropy-core/pull/843)) - Add support for `--mnemonic-file` and `THRESHOLD_SERVER_MNEMONIC` ([#864](https://github.com/entropyxyz/entropy-core/pull/864)) - Add validator helpers to cli ([#870](https://github.com/entropyxyz/entropy-core/pull/870)) -- Add blake2 as built in hash function and make HashingAlgorithm non-exhaustive ([#881](https://github.com/entropyxyz/entropy-core/pull/881) +- Add blake2 as built in hash function and make HashingAlgorithm non-exhaustive ([#881](https://github.com/entropyxyz/entropy-core/pull/881)) +- Add sort to subgroup signer selection ([#900](https://github.com/entropyxyz/entropy-core/pull/900)) ### Changed - Move TSS mnemonic out of keystore [#853](https://github.com/entropyxyz/entropy-core/pull/853) diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index b1269d64f..34ff132dc 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -61,11 +61,11 @@ pub async fn get_current_subgroup_signers( async move { let subgroup_info_query = entropy::storage().staking_extension().signing_groups(i as u8); - let subgroup_info = - query_chain(api, rpc, subgroup_info_query, block_hash) - .await? - .ok_or_else(|| SubgroupGetError::ChainFetch("Subgroup Fetch Error"))?; - + let mut subgroup_info = query_chain(api, rpc, subgroup_info_query, block_hash) + .await? + .ok_or_else(|| SubgroupGetError::ChainFetch("Subgroup Fetch Error"))?; + // sort subgroup for ease in client side calculations + subgroup_info.sort(); let index_of_signer_big = &*owned_number % subgroup_info.len(); let index_of_signer = index_of_signer_big.to_usize().ok_or(SubgroupGetError::Usize("Usize error"))?; diff --git a/crates/threshold-signature-server/src/lib.rs b/crates/threshold-signature-server/src/lib.rs index d3bca4946..1690b6bc0 100644 --- a/crates/threshold-signature-server/src/lib.rs +++ b/crates/threshold-signature-server/src/lib.rs @@ -151,7 +151,7 @@ use validator::api::get_random_server_info; use crate::{ health::api::healthz, launch::Configuration, - node_info::api::{hashes, version as get_version}, + node_info::api::{get_subgroup_signers, hashes, version as get_version}, r#unsafe::api::{delete, put, remove_keys, unsafe_get}, signing_client::{api::*, ListenerState}, user::api::*, @@ -185,6 +185,7 @@ pub fn app(app_state: AppState) -> Router { .route("/user/receive_key", post(receive_key)) .route("/signer/proactive_refresh", post(proactive_refresh)) .route("/validator/sync_kvdb", post(sync_kvdb)) + .route("/subgroup_signers", post(get_subgroup_signers)) .route("/healthz", get(healthz)) .route("/version", get(get_version)) .route("/hashes", get(hashes)) diff --git a/crates/threshold-signature-server/src/node_info/api.rs b/crates/threshold-signature-server/src/node_info/api.rs index e5ca0541d..e310a33e6 100644 --- a/crates/threshold-signature-server/src/node_info/api.rs +++ b/crates/threshold-signature-server/src/node_info/api.rs @@ -12,9 +12,16 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use axum::Json; +use crate::{ + chain_api::{get_api, get_rpc}, + user::UserErr, + AppState, +}; +use axum::{extract::State, Json}; +pub use entropy_client::user::get_current_subgroup_signers; use entropy_shared::types::HashingAlgorithm; use strum::IntoEnumIterator; + /// Returns the version and commit data #[tracing::instrument] pub async fn version() -> String { @@ -26,3 +33,18 @@ pub async fn hashes() -> Json> { let hashing_algos = HashingAlgorithm::iter().collect::>(); Json(hashing_algos) } + +/// Returns the list of subgroup signers given a message hash. +/// +/// Note: the message hash should not include a preceding `0x`. +#[tracing::instrument(skip_all)] +pub async fn get_subgroup_signers( + State(app_state): State, + message_hash: String, +) -> Result { + tracing::debug!("Message hash {:?}", message_hash); + let api = get_api(&app_state.configuration.endpoint).await?; + let rpc = get_rpc(&app_state.configuration.endpoint).await?; + let subgroup_signers = get_current_subgroup_signers(&api, &rpc, &message_hash).await?; + Ok(serde_json::to_string(&subgroup_signers)?) +} diff --git a/crates/threshold-signature-server/src/node_info/tests.rs b/crates/threshold-signature-server/src/node_info/tests.rs index 19c33c564..74ade5ec8 100644 --- a/crates/threshold-signature-server/src/node_info/tests.rs +++ b/crates/threshold-signature-server/src/node_info/tests.rs @@ -13,7 +13,14 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::helpers::tests::{initialize_test_logger, setup_client}; +use crate::{ + chain_api::{get_api, get_rpc}, + helpers::tests::{initialize_test_logger, setup_client, spawn_testing_validators}, +}; +use entropy_client::user::get_current_subgroup_signers; +use entropy_testing_utils::substrate_context::test_context_stationary; + +use entropy_kvdb::clean_tests; use entropy_shared::types::HashingAlgorithm; use serial_test::serial; @@ -50,3 +57,31 @@ async fn hashes_test() { ] ); } + +#[tokio::test] +#[serial] +async fn test_get_subgroup() { + initialize_test_logger().await; + clean_tests(); + + let _ = spawn_testing_validators(None, false, false).await; + let substrate_context = test_context_stationary().await; + let api = get_api(&substrate_context.node_proc.ws_url).await.unwrap(); + let rpc = get_rpc(&substrate_context.node_proc.ws_url).await.unwrap(); + let mock_client = reqwest::Client::new(); + // example keccak hash + let message_hash = "06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2"; + let response = mock_client + .post("http://127.0.0.1:3001/subgroup_signers") + .header("Content-Type", "application/json") + .body(message_hash) + .send() + .await; + let mock_result = get_current_subgroup_signers(&api, &rpc, &message_hash).await.unwrap(); + assert_eq!( + serde_json::to_string(&mock_result).unwrap(), + response.unwrap().text().await.unwrap(), + "subgroup data should match" + ); + clean_tests(); +} diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index 0e1058a07..7aa1982ba 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -1760,7 +1760,7 @@ async fn test_faucet() { .await .unwrap(); - let amount_to_send = 200000011; + let amount_to_send = 200000012; let faucet_user_config = UserConfig { max_transfer_amount: amount_to_send }; update_programs(