Skip to content

Commit

Permalink
Remove subgroups from jumpstart (#936)
Browse files Browse the repository at this point in the history
* Remove subgroups from jumpstart code

* Bump metadata

* Remove subgroup from TSS call

* Try and update benches

* fix failing benchmark

* Get tests compiling

* Remove tests related to key syncing

* Add check that validator is actually in set and not just a candidate

* Remove commented code

* Appease Clippy

* Remove commented code

* Add third validator to jumpstart tests

* Remove `KeyVisiblity` from registry tests

* Switch to `KeyShareWithAuxInfo`

* Don't use with `WithAuxInfo` variant

* Add validators to benchmark validator set

* Add ID of validator which confirmed jump start to event

* Fix some formatting

* add aux info back into key

* fix jumpstart test

---------

Co-authored-by: Jesse Abramowitz <[email protected]>
  • Loading branch information
HCastano and JesseAbram authored Jul 16, 2024
1 parent 7358188 commit ae0de93
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 359 deletions.
Binary file modified crates/client/entropy_metadata.scale
Binary file not shown.
13 changes: 2 additions & 11 deletions crates/threshold-signature-server/src/user/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,14 +292,6 @@ async fn setup_dkg(
app_state: AppState,
) -> Result<(), UserErr> {
tracing::debug!("Preparing to execute DKG");
// let block_hash = rpc
// .chain_get_block_hash(None)
// .await?
// .ok_or_else(|| UserErr::OptionUnwrapError("Error getting block hash".to_string()))?;
// let nonce_call = entropy::apis().account_nonce_api().account_nonce(signer.account_id().clone());
// let nonce = api.runtime_api().at(block_hash).call(nonce_call).await?;

// for (i, sig_request_account) in data.sig_request_accounts.into_iter().enumerate() {
for sig_request_account in data.sig_request_accounts.into_iter() {
let address_slice: &[u8; 32] = &sig_request_account
.clone()
Expand All @@ -324,7 +316,7 @@ async fn setup_dkg(
}
.to_string();

let serialized_key_share = key_serialize(&key_share)
let serialized_key_share = key_serialize(&(key_share, aux_info))
.map_err(|_| UserErr::KvSerialize("Kv Serialize Error".to_string()))?;

let reservation = app_state.kv_store.kv().reserve_key(string_verifying_key.clone()).await?;
Expand Down Expand Up @@ -389,8 +381,7 @@ pub async fn confirm_registered(
// TODO: Understand this better, potentially use sign_and_submit_default
// or other method under sign_and_*
if who.encode() == NETWORK_PARENT_KEY.encode() {
// TODO (Nando): Remove the subgroup argument
let jump_start_request = entropy::tx().registry().confirm_jump_start(0);
let jump_start_request = entropy::tx().registry().confirm_jump_start();
submit_transaction(api, rpc, signer, &jump_start_request, Some(nonce)).await?;
} else {
let confirm_register_request = entropy::tx().registry().confirm_register(
Expand Down
308 changes: 28 additions & 280 deletions crates/threshold-signature-server/src/user/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,14 +722,14 @@ async fn test_jumpstart_network() {
let alice = AccountKeyring::Alice;

let cxt = test_context_stationary().await;
let (_validator_ips, _validator_ids, _) =
spawn_testing_validators(Some(DEFAULT_VERIFYING_KEY.to_vec()), false, false).await;
let (_validator_ips, _validator_ids) = spawn_testing_validators().await;
let api = get_api(&cxt.node_proc.ws_url).await.unwrap();
let rpc = get_rpc(&cxt.node_proc.ws_url).await.unwrap();

let client = reqwest::Client::new();

let block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number + 1;

let validators_info = vec![
entropy_shared::ValidatorInfo {
ip_address: b"127.0.0.1:3001".to_vec(),
Expand All @@ -741,6 +741,11 @@ async fn test_jumpstart_network() {
x25519_public_key: X25519_PUBLIC_KEYS[1],
tss_account: TSS_ACCOUNTS[1].clone().encode(),
},
entropy_shared::ValidatorInfo {
ip_address: b"127.0.0.1:3003".to_vec(),
x25519_public_key: X25519_PUBLIC_KEYS[2],
tss_account: TSS_ACCOUNTS[2].clone().encode(),
},
];
let onchain_user_request = OcwMessageDkg {
sig_request_accounts: vec![NETWORK_PARENT_KEY.encode()],
Expand All @@ -753,14 +758,23 @@ async fn test_jumpstart_network() {
run_to_block(&rpc, block_number + 1).await;

// succeeds
let user_registration_response = client
.post("http://127.0.0.1:3002/user/new")
.body(onchain_user_request.clone().encode())
.send()
.await
.unwrap();
let response_results = join_all(
vec![3002, 3003]
.iter()
.map(|port| {
client
.post(format!("http://127.0.0.1:{}/user/new", port))
.body(onchain_user_request.clone().encode())
.send()
})
.collect::<Vec<_>>(),
)
.await;

for response_result in response_results {
assert_eq!(response_result.unwrap().text().await.unwrap(), "");
}

assert_eq!(user_registration_response.text().await.unwrap(), "");
// wait for jump start event check that key exists in kvdb
for _ in 0..45 {
std::thread::sleep(std::time::Duration::from_millis(1000));
Expand All @@ -772,279 +786,13 @@ async fn test_jumpstart_network() {
}
}

let get_query = UnsafeQuery::new(hex::encode(NETWORK_PARENT_KEY), [].to_vec()).to_json();
// check get key before registration to see if key gets replaced
let response_key = client
.post("http://127.0.0.1:3001/unsafe/get")
.header("Content-Type", "application/json")
.body(get_query.clone())
.send()
.await
.unwrap();
let response_key = unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), 3001).await;

// check to make sure keyshare is correct
let key_share: Option<KeyShare<KeyParams>> =
entropy_kvdb::kv_manager::helpers::deserialize(&response_key.bytes().await.unwrap());
let key_share: Option<KeyShareWithAuxInfo> =
entropy_kvdb::kv_manager::helpers::deserialize(&response_key);
assert_eq!(key_share.is_some(), true);
clean_tests();
}

#[tokio::test]
#[serial]
async fn test_return_addresses_of_subgroup() {
initialize_test_logger().await;

let cxt = test_context_stationary().await;
let api = get_api(&cxt.node_proc.ws_url).await.unwrap();
let rpc = get_rpc(&cxt.node_proc.ws_url).await.unwrap();

let result = return_all_addresses_of_subgroup(&api, &rpc, 0u8).await.unwrap();
assert_eq!(result.len(), 1);
}

#[tokio::test]
#[serial]
async fn test_send_and_receive_keys() {
initialize_test_logger().await;
clean_tests();

let alice = AccountKeyring::Alice;
let program_manager = AccountKeyring::Dave;
let signature_request_account = subxtAccountId32(alice.pair().public().0);

let cxt = test_context_stationary().await;
setup_client().await;
let api = get_api(&cxt.node_proc.ws_url).await.unwrap();
let rpc = get_rpc(&cxt.node_proc.ws_url).await.unwrap();

let share = {
let share = &KeyShare::<KeyParams>::new_centralized(&mut rand_core::OsRng, 2, None)[0];
entropy_kvdb::kv_manager::helpers::serialize(&share).unwrap()
};

let user_registration_info = UserRegistrationInfo {
key: alice.to_account_id().to_string(),
value: share.clone(),
proactive_refresh: false,
sig_request_address: Some(signature_request_account.clone()),
};

let (signer_alice, _) = get_signer_and_x25519_secret_from_mnemonic(DEFAULT_MNEMONIC).unwrap();

// First try sending a keyshare for a user who is not registering - should fail
let result = send_key(
&api,
&rpc,
&alice.to_account_id().into(),
&mut vec![ALICE_STASH_ADDRESS.clone(), alice.to_account_id().into()],
user_registration_info.clone(),
&signer_alice,
)
.await;

if let Err(UserErr::KeyShareRejected(error_message)) = result {
assert_eq!(
error_message,
"Not Registering error: Provided account ID not from a registering user".to_string()
);
} else {
panic!("Should give not registering error");
}

// The happy path - the user is in a registering state - should succeed
let program_hash = store_program(
&api,
&rpc,
&program_manager.pair(),
TEST_PROGRAM_WASM_BYTECODE.to_owned(),
vec![],
vec![],
vec![],
)
.await
.unwrap();

put_register_request_on_chain(
&api,
&rpc,
&alice.clone(),
alice.to_account_id().into(),
KeyVisibility::Public,
BoundedVec(vec![ProgramInstance { program_pointer: program_hash, program_config: vec![] }]),
)
.await;

// sends key to alice validator, while filtering out own key
send_key(
&api,
&rpc,
&alice.to_account_id().into(),
&mut vec![ALICE_STASH_ADDRESS.clone(), alice.to_account_id().into()],
user_registration_info.clone(),
&signer_alice,
)
.await
.unwrap();

let get_query = UnsafeQuery::new(user_registration_info.key.clone(), vec![]).to_json();

let client = reqwest::Client::new();
// check alice has new key
let response_new_key = client
.post("http://127.0.0.1:3001/unsafe/get")
.header("Content-Type", "application/json")
.body(get_query.clone())
.send()
.await
.unwrap();

assert_eq!(response_new_key.bytes().await.unwrap(), &user_registration_info.value.clone());

// A keyshare can be overwritten when the user is still in a registering state
let some_other_share = {
let share = &KeyShare::<KeyParams>::new_centralized(&mut rand_core::OsRng, 2, None)[0];
entropy_kvdb::kv_manager::helpers::serialize(&share).unwrap()
};

let user_registration_info_overwrite = UserRegistrationInfo {
key: alice.to_account_id().to_string(),
value: some_other_share.clone(),
proactive_refresh: false,
sig_request_address: Some(signature_request_account.clone()),
};

let signed_message = serde_json::to_string(
&EncryptedSignedMessage::new(
signer_alice.signer(),
serde_json::to_vec(&user_registration_info_overwrite).unwrap(),
&X25519_PUBLIC_KEYS[0],
&[],
)
.unwrap(),
)
.unwrap();

let response_overwrites_key = client
.post("http://127.0.0.1:3001/user/receive_key")
.header("Content-Type", "application/json")
.body(signed_message.clone())
.send()
.await
.unwrap();

assert_eq!(response_overwrites_key.status(), StatusCode::OK);
assert_eq!(response_overwrites_key.text().await.unwrap(), "");

// Check that the key has been successfully overwritten
let get_query = UnsafeQuery::new(user_registration_info.key.clone(), vec![]).to_json();
let response_new_key = client
.post("http://127.0.0.1:3001/unsafe/get")
.header("Content-Type", "application/json")
.body(get_query.clone())
.send()
.await
.unwrap();

assert_eq!(response_new_key.bytes().await.unwrap(), &some_other_share);

// Try writing a 'forbidden key' - should fail
let user_registration_info_forbidden = UserRegistrationInfo {
key: "MNEMONIC".to_string(),
value: share.clone(),
proactive_refresh: false,
sig_request_address: Some(signature_request_account.clone()),
};

let signed_message = serde_json::to_string(
&EncryptedSignedMessage::new(
signer_alice.signer(),
serde_json::to_vec(&user_registration_info_forbidden).unwrap(),
&X25519_PUBLIC_KEYS[0],
&[],
)
.unwrap(),
)
.unwrap();

let response_overwrites_key = client
.post("http://127.0.0.1:3001/user/receive_key")
.header("Content-Type", "application/json")
.body(signed_message.clone())
.send()
.await
.unwrap();

assert_eq!(response_overwrites_key.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(response_overwrites_key.text().await.unwrap(), "The given key is forbidden");

// Try sending a badly formed keyshare - should fail
let user_registration_info_bad_keyshare = UserRegistrationInfo {
key: alice.to_account_id().to_string(),
value: b"This will not deserialize to KeyShare<KeyParams>".to_vec(),
proactive_refresh: false,
sig_request_address: Some(signature_request_account.clone()),
};

let signed_message = serde_json::to_string(
&EncryptedSignedMessage::new(
signer_alice.signer(),
serde_json::to_vec(&user_registration_info_bad_keyshare).unwrap(),
&X25519_PUBLIC_KEYS[0],
&[],
)
.unwrap(),
)
.unwrap();

let response_overwrites_key = client
.post("http://127.0.0.1:3001/user/receive_key")
.header("Content-Type", "application/json")
.body(signed_message.clone())
.send()
.await
.unwrap();

assert_eq!(response_overwrites_key.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
response_overwrites_key.text().await.unwrap(),
"Input Validation error: Not a valid keyshare"
);

clean_tests();
}

#[tokio::test]
#[serial]
async fn test_recover_key() {
initialize_test_logger().await;
clean_tests();

let cxt = test_node_process_testing_state(false).await;
setup_client().await;
let (_, bob_kv) =
create_clients("validator2".to_string(), vec![], vec![], &Some(ValidatorName::Bob)).await;

let api = get_api(&cxt.ws_url).await.unwrap();
let rpc = get_rpc(&cxt.ws_url).await.unwrap();
let unsafe_query = UnsafeQuery::new("key".to_string(), vec![10]);
let client = reqwest::Client::new();

let _ = client
.post("http://127.0.0.1:3001/unsafe/put")
.header("Content-Type", "application/json")
.body(unsafe_query.clone().to_json())
.send()
.await
.unwrap();

let (signer_alice, x25519_alice) =
get_signer_and_x25519_secret_from_mnemonic(DEFAULT_CHARLIE_MNEMONIC).unwrap();

recover_key(&api, &rpc, &bob_kv, &signer_alice, &x25519_alice, unsafe_query.key.clone())
.await
.unwrap();

let value = bob_kv.kv().get(&unsafe_query.key).await.unwrap();
assert_eq!(value, unsafe_query.value);
clean_tests();
}

Expand Down Expand Up @@ -1377,7 +1125,7 @@ async fn test_faucet() {
let entropy_api = get_api(&substrate_context.ws_url).await.unwrap();
let rpc = get_rpc(&substrate_context.ws_url).await.unwrap();

let verifying_key = EVE_VERIFYING_KEY; //keyshare_option.clone().unwrap().verifying_key().to_encoded_point(true).as_bytes().to_vec();
let verifying_key = EVE_VERIFYING_KEY;
let verfiying_key_account_hash = blake2_256(&verifying_key);
let verfiying_key_account = subxtAccountId32(verfiying_key_account_hash);

Expand Down
Loading

0 comments on commit ae0de93

Please sign in to comment.