use std::net::{TcpListener, TcpStream};
use iota_network_stack::Multiaddr;
use rand::{SeedableRng as _, rngs::StdRng};
use crate::{
Authority, AuthorityKeyPair, Committee, Epoch, NetworkKeyPair, ProtocolKeyPair, Stake,
};
pub fn local_committee_and_keys(
epoch: Epoch,
authorities_stake: Vec<Stake>,
) -> (Committee, Vec<(NetworkKeyPair, ProtocolKeyPair)>) {
let mut authorities = vec![];
let mut key_pairs = vec![];
let mut rng = StdRng::from_seed([0; 32]);
for (i, stake) in authorities_stake.into_iter().enumerate() {
let authority_keypair = AuthorityKeyPair::generate(&mut rng);
let protocol_keypair = ProtocolKeyPair::generate(&mut rng);
let network_keypair = NetworkKeyPair::generate(&mut rng);
authorities.push(Authority {
stake,
address: get_available_local_address(),
hostname: format!("test_host_{i}").to_string(),
authority_key: authority_keypair.public(),
protocol_key: protocol_keypair.public(),
network_key: network_keypair.public(),
});
key_pairs.push((network_keypair, protocol_keypair));
}
let committee = Committee::new(epoch, authorities);
(committee, key_pairs)
}
fn get_available_local_address() -> Multiaddr {
let host = "127.0.0.1";
let port = get_available_port(host);
format!("/ip4/{}/udp/{}", host, port).parse().unwrap()
}
fn get_available_port(host: &str) -> u16 {
const MAX_PORT_RETRIES: u32 = 1000;
for _ in 0..MAX_PORT_RETRIES {
if let Ok(port) = get_ephemeral_port(host) {
return port;
}
}
panic!("Error: could not find an available port");
}
fn get_ephemeral_port(host: &str) -> std::io::Result<u16> {
let listener = TcpListener::bind((host, 0))?;
let addr = listener.local_addr()?;
let _sender = TcpStream::connect(addr)?;
let _incoming = listener.accept()?;
Ok(addr.port())
}