Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove subgroups from jumpstart #936

Merged
merged 20 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,22 +292,14 @@ 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()
.try_into()
.map_err(|_| UserErr::AddressConversionError("Invalid Length".to_string()))?;
let sig_request_address = SubxtAccountId32(*address_slice);

let (key_share, aux_info) = do_dkg(
let (key_share, _aux_info) = do_dkg(
&data.validators_info,
&signer,
x25519_secret_key,
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<ThresholdKeyShare<KeyParams, entropy_protocol::PartyId>> =
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