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

Add set_identity tests #3794

Merged
merged 6 commits into from
Dec 2, 2024
Merged
Changes from all 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
195 changes: 191 additions & 4 deletions validator/src/admin_rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,10 +869,18 @@ mod tests {
accounts_db::{AccountsDbConfig, ACCOUNTS_DB_CONFIG_FOR_TESTING},
accounts_index::AccountSecondaryIndexes,
},
solana_core::consensus::tower_storage::NullTowerStorage,
solana_gossip::cluster_info::ClusterInfo,
solana_core::{
consensus::tower_storage::NullTowerStorage,
validator::{Validator, ValidatorConfig},
},
solana_gossip::cluster_info::{ClusterInfo, Node},
solana_inline_spl::token,
solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo},
solana_ledger::{
create_new_tmp_ledger,
genesis_utils::{
create_genesis_config, create_genesis_config_with_leader, GenesisConfigInfo,
},
},
solana_net_utils::bind_to_unspecified,
solana_rpc::rpc::create_validator_exit,
solana_runtime::{
Expand All @@ -885,11 +893,14 @@ mod tests {
system_program,
},
solana_streamer::socket::SocketAddrSpace,
solana_tpu_client::tpu_client::{
DEFAULT_TPU_CONNECTION_POOL_SIZE, DEFAULT_TPU_ENABLE_UDP, DEFAULT_TPU_USE_QUIC,
},
spl_token_2022::{
solana_program::{program_option::COption, program_pack::Pack},
state::{Account as TokenAccount, AccountState as TokenAccountState, Mint},
},
std::{collections::HashSet, sync::atomic::AtomicBool},
std::{collections::HashSet, fs::remove_dir_all, sync::atomic::AtomicBool},
};

#[derive(Default)]
Expand Down Expand Up @@ -1287,4 +1298,180 @@ mod tests {
}
}
}

// This test checks that the rpc call to `set_identity` works a expected with
// Bank but without validator.
#[test]
fn test_set_identity() {
let rpc = RpcHandler::start_with_config(TestConfig::default());

let RpcHandler { io, meta, .. } = rpc;

let expected_validator_id = Keypair::new();
let validator_id_bytes = format!("{:?}", expected_validator_id.to_bytes());

let set_id_request = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"setIdentityFromBytes","params":[{validator_id_bytes}, false]}}"#,
);
let response = io.handle_request_sync(&set_id_request, meta.clone());
let actual_parsed_response: Value =
serde_json::from_str(&response.expect("actual response"))
.expect("actual response deserialization");

let expected_parsed_response: Value = serde_json::from_str(
r#"{
"id": 1,
"jsonrpc": "2.0",
"result": null
}"#,
)
.expect("Failed to parse expected response");
assert_eq!(actual_parsed_response, expected_parsed_response);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feels a little fragile. Could we just check for null result so that we don't have to update this for benign things like a version change?


let contact_info_request =
r#"{"jsonrpc":"2.0","id":1,"method":"contactInfo","params":[]}"#.to_string();
let response = io.handle_request_sync(&contact_info_request, meta.clone());
let parsed_response: Value = serde_json::from_str(&response.expect("actual response"))
.expect("actual response deserialization");
let actual_validator_id = parsed_response["result"]["id"]
.as_str()
.expect("Expected a string");
assert_eq!(
actual_validator_id,
expected_validator_id.pubkey().to_string()
);
}

struct TestValidatorWithAdminRpc {
meta: AdminRpcRequestMetadata,
io: MetaIoHandler<AdminRpcRequestMetadata>,
validator_ledger_path: PathBuf,
}

impl TestValidatorWithAdminRpc {
fn new() -> Self {
let leader_keypair = Keypair::new();
let leader_node = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());

let validator_keypair = Keypair::new();
let validator_node = Node::new_localhost_with_pubkey(&validator_keypair.pubkey());
let genesis_config =
create_genesis_config_with_leader(10_000, &leader_keypair.pubkey(), 1000)
.genesis_config;
let (validator_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);

let voting_keypair = Arc::new(Keypair::new());
let voting_pubkey = voting_keypair.pubkey();
let authorized_voter_keypairs = Arc::new(RwLock::new(vec![voting_keypair]));
let validator_config = ValidatorConfig {
rpc_addrs: Some((
validator_node.info.rpc().unwrap(),
validator_node.info.rpc_pubsub().unwrap(),
)),
..ValidatorConfig::default_for_test()
};
let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));

let post_init = Arc::new(RwLock::new(None));
let meta = AdminRpcRequestMetadata {
rpc_addr: validator_config.rpc_addrs.map(|(rpc_addr, _)| rpc_addr),
start_time: SystemTime::now(),
start_progress: start_progress.clone(),
validator_exit: validator_config.validator_exit.clone(),
authorized_voter_keypairs: authorized_voter_keypairs.clone(),
tower_storage: Arc::new(NullTowerStorage {}),
post_init: post_init.clone(),
staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
rpc_to_plugin_manager_sender: None,
};

let _validator = Validator::new(
validator_node,
Arc::new(validator_keypair),
&validator_ledger_path,
&voting_pubkey,
authorized_voter_keypairs,
vec![leader_node.info],
&validator_config,
true, // should_check_duplicate_instance
None, // rpc_to_plugin_manager_receiver
start_progress.clone(),
SocketAddrSpace::Unspecified,
DEFAULT_TPU_USE_QUIC,
DEFAULT_TPU_CONNECTION_POOL_SIZE,
DEFAULT_TPU_ENABLE_UDP,
32, // max connections per IpAddr per minute for test
post_init,
)
.expect("assume successful validator start");
assert_eq!(
*start_progress.read().unwrap(),
ValidatorStartProgress::Running
);
let mut io = MetaIoHandler::default();
io.extend_with(AdminRpcImpl.to_delegate());
Self {
meta,
io,
validator_ledger_path,
}
}

fn handle_request(&self, request: &str) -> Option<String> {
self.io.handle_request_sync(request, self.meta.clone())
}
}

impl Drop for TestValidatorWithAdminRpc {
fn drop(&mut self) {
remove_dir_all(self.validator_ledger_path.clone()).unwrap();
}
}

// This test checks that `set_identity` call works with working validator and client.
#[test]
fn test_set_identity_with_validator() {
let test_validator = TestValidatorWithAdminRpc::new();
let expected_validator_id = Keypair::new();
let validator_id_bytes = format!("{:?}", expected_validator_id.to_bytes());

let set_id_request = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"setIdentityFromBytes","params":[{validator_id_bytes}, false]}}"#,
);
let response = test_validator.handle_request(&set_id_request);
let actual_parsed_response: Value =
serde_json::from_str(&response.expect("actual response"))
.expect("actual response deserialization");

let expected_parsed_response: Value = serde_json::from_str(
r#"{
"id": 1,
"jsonrpc": "2.0",
"result": null
}"#,
)
.expect("Failed to parse expected response");
assert_eq!(actual_parsed_response, expected_parsed_response);

let contact_info_request =
r#"{"jsonrpc":"2.0","id":1,"method":"contactInfo","params":[]}"#.to_string();
let response = test_validator.handle_request(&contact_info_request);
let parsed_response: Value = serde_json::from_str(&response.expect("actual response"))
.expect("actual response deserialization");
let actual_validator_id = parsed_response["result"]["id"]
.as_str()
.expect("Expected a string");
assert_eq!(
actual_validator_id,
expected_validator_id.pubkey().to_string()
);

let contact_info_request =
Copy link
Author

@KirillLykov KirillLykov Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it also tests that exit call works properly but this is not reflected in the name of the test.

r#"{"jsonrpc":"2.0","id":1,"method":"exit","params":[]}"#.to_string();
let exit_response = test_validator.handle_request(&contact_info_request);
let actual_parsed_response: Value =
serde_json::from_str(&exit_response.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(actual_parsed_response, expected_parsed_response);
}
}
Loading