diff --git a/fullnode/src/main.rs b/fullnode/src/main.rs index 36ec127c4f..3126bfdd4d 100644 --- a/fullnode/src/main.rs +++ b/fullnode/src/main.rs @@ -1,14 +1,10 @@ -extern crate serde_json; - use clap::{crate_version, App, Arg, ArgMatches}; use log::*; - use solana::client::mk_client; use solana::cluster_info::{Node, NodeInfo, FULLNODE_PORT_RANGE}; -use solana::fullnode::{Fullnode, FullnodeReturnType}; +use solana::fullnode::Fullnode; use solana::leader_scheduler::LeaderScheduler; use solana::local_vote_signer_service::LocalVoteSignerService; -use solana::service::Service; use solana::socketaddr; use solana::thin_client::{poll_gossip_for_leader, ThinClient}; use solana::vote_signer_proxy::{RemoteVoteSigner, VoteSignerProxy}; @@ -58,10 +54,9 @@ fn create_and_fund_vote_account( node_keypair: &Arc, ) -> Result<()> { let pubkey = node_keypair.pubkey(); - let balance = client.poll_get_balance(&pubkey).unwrap_or(0); - info!("balance is {}", balance); - if balance < 1 { - error!("insufficient tokens, one token required"); + let node_balance = client.poll_get_balance(&pubkey)?; + info!("node balance is {}", node_balance); + if node_balance < 1 { return Err(Error::new( ErrorKind::Other, "insufficient tokens, one token required", @@ -71,7 +66,7 @@ fn create_and_fund_vote_account( // Create the vote account if necessary if client.poll_get_balance(&vote_account).unwrap_or(0) == 0 { // Need at least two tokens as one token will be spent on a vote_account_new() transaction - if balance < 2 { + if node_balance < 2 { error!("insufficient tokens, two tokens required"); return Err(Error::new( ErrorKind::Other, @@ -82,56 +77,45 @@ fn create_and_fund_vote_account( let last_id = client.get_last_id(); let transaction = VoteTransaction::vote_account_new(node_keypair, vote_account, last_id, 1, 1); - if client.transfer_signed(&transaction).is_err() { - sleep(Duration::from_secs(2)); - continue; - } - let balance = client.poll_get_balance(&vote_account).unwrap_or(0); - if balance > 0 { - break; - } + match client.transfer_signed(&transaction) { + Ok(_) => match client.poll_get_balance(&vote_account) { + Ok(balance) => { + info!("vote account balance: {}", balance); + break; + } + Err(e) => { + info!("Failed to get vote account balance: {:?}", e); + } + }, + Err(e) => { + info!("Failed to send vote_account_new transaction: {:?}", e); + } + }; sleep(Duration::from_secs(2)); } } - Ok(()) -} -fn wait_for_vote_account_registeration( - client: &mut ThinClient, - vote_account: &Pubkey, - node_id: Pubkey, -) { - loop { - let vote_account_user_data = client.get_account_userdata(vote_account); - if let Ok(Some(vote_account_user_data)) = vote_account_user_data { - if let Ok(vote_state) = VoteProgram::deserialize(&vote_account_user_data) { - if vote_state.node_id == node_id { - break; - } - } - } - panic!("Expected successful vote account registration"); - } -} - -fn run_forever_and_do_role_transition(fullnode: &mut Fullnode) { - loop { - let status = fullnode.handle_role_transition(); - match status { - Ok(Some(FullnodeReturnType::LeaderToValidatorRotation)) => (), - Ok(Some(FullnodeReturnType::ValidatorToLeaderRotation)) => (), - _ => { - // Fullnode tpu/tvu exited for some unexpected reason - return; + debug!("Checking for vote account registration"); + let vote_account_user_data = client.get_account_userdata(&vote_account); + if let Ok(Some(vote_account_user_data)) = vote_account_user_data { + if let Ok(vote_state) = VoteProgram::deserialize(&vote_account_user_data) { + if vote_state.node_id == pubkey { + return Ok(()); } } } + + Err(Error::new( + ErrorKind::Other, + "expected successful vote account registration", + )) } fn main() { solana_logger::setup(); solana_metrics::set_panic_hook("fullnode"); + let matches = App::new("fullnode") .version(crate_version!()) .arg( @@ -159,7 +143,7 @@ fn main() { .long("network") .value_name("HOST:PORT") .takes_value(true) - .help("Rendezvous with the network at this gossip entry point"), + .help("Rendezvous with the cluster at this gossip entry point"), ) .arg( Arg::with_name("signer") @@ -187,69 +171,49 @@ fn main() { ) .get_matches(); - let nosigverify = matches.is_present("nosigverify"); + let no_sigverify = matches.is_present("nosigverify"); let use_only_bootstrap_leader = matches.is_present("no-leader-rotation"); - let (keypair, gossip) = parse_identity(&matches); - let ledger_path = matches.value_of("ledger").unwrap(); - - // socketaddr that is initial pointer into the network's gossip - let network = matches + let cluster_entrypoint = matches .value_of("network") .map(|network| network.parse().expect("failed to parse network address")); - - let node = Node::new_with_external_ip(keypair.pubkey(), &gossip); - - let keypair = Arc::new(keypair); - let pubkey = keypair.pubkey(); - - let mut leader_scheduler = LeaderScheduler::default(); - leader_scheduler.use_only_bootstrap_leader = use_only_bootstrap_leader; - + let (_signer_service, signer_addr) = if let Some(signer_addr) = matches.value_of("signer") { + ( + None, + signer_addr.to_string().parse().expect("Signer IP Address"), + ) + } else { + // Run a local vote signer if a vote signer service address was not provided + let (signer_service, signer_addr) = LocalVoteSignerService::new(); + (Some(signer_service), signer_addr) + }; let rpc_port = if let Some(port) = matches.value_of("rpc_port") { let port_number = port.to_string().parse().expect("integer"); if port_number == 0 { eprintln!("Invalid RPC port requested: {:?}", port); exit(1); } - Some(port_number) + port_number } else { - match solana_netutil::find_available_port_in_range(FULLNODE_PORT_RANGE) { - Ok(port) => Some(port), - Err(_) => None, - } + solana_netutil::find_available_port_in_range(FULLNODE_PORT_RANGE) + .expect("unable to allocate rpc port") }; - let leader = match network { - Some(network) => { - poll_gossip_for_leader(network, None).expect("can't find leader on network") - } - None => { - //self = leader - let mut node_info = node.info.clone(); - if rpc_port.is_some() { - node_info.rpc.set_port(rpc_port.unwrap()); - node_info.rpc_pubsub.set_port(rpc_port.unwrap() + 1); - } - node_info - } - }; + let keypair = Arc::new(keypair); + let node = Node::new_with_external_ip(keypair.pubkey(), &gossip); + let mut node_info = node.info.clone(); + node_info.rpc.set_port(rpc_port); + node_info.rpc_pubsub.set_port(rpc_port + 1); - let (signer_service, signer) = if let Some(signer_addr) = matches.value_of("signer") { - ( - None, - signer_addr.to_string().parse().expect("Signer IP Address"), - ) - } else { - // If a remote vote-signer service is not provided, run a local instance - let (signer_service, addr) = LocalVoteSignerService::new(); - (Some(signer_service), addr) - }; + let mut leader_scheduler = LeaderScheduler::default(); + leader_scheduler.use_only_bootstrap_leader = use_only_bootstrap_leader; - let mut client = mk_client(&leader); - let vote_signer = VoteSignerProxy::new(&keypair, Box::new(RemoteVoteSigner::new(signer))); + let vote_signer = VoteSignerProxy::new(&keypair, Box::new(RemoteVoteSigner::new(signer_addr))); let vote_account = vote_signer.vote_account; + + info!("Node ID: {}", node.info.id); + info!("Signer service address: {:?}", signer_addr); info!("New vote account ID is {:?}", vote_account); let mut fullnode = Fullnode::new( @@ -257,25 +221,44 @@ fn main() { ledger_path, keypair.clone(), Arc::new(vote_signer), - network, - nosigverify, + cluster_entrypoint, + no_sigverify, leader_scheduler, - rpc_port, + Some(rpc_port), ); - if create_and_fund_vote_account(&mut client, vote_account, &keypair).is_err() { - if let Some(signer_service) = signer_service { - signer_service.join().unwrap(); + { + let leader_node_info = loop { + info!("Looking for leader..."); + match poll_gossip_for_leader(node_info.gossip, Some(10)) { + Ok(leader_node_info) => { + info!("Found leader: {:?}", leader_node_info); + break leader_node_info; + } + Err(err) => { + info!("Unable to find leader: {:?}", err); + } + }; + }; + + let mut client = mk_client(&leader_node_info); + if let Err(err) = create_and_fund_vote_account(&mut client, vote_account, &keypair) { + panic!("Failed to create_and_fund_vote_account: {:?}", err); } - exit(1); } - wait_for_vote_account_registeration(&mut client, &vote_account, pubkey); - run_forever_and_do_role_transition(&mut fullnode); - - if let Some(signer_service) = signer_service { - signer_service.join().unwrap(); + loop { + let status = fullnode.handle_role_transition(); + match status { + Ok(Some(transition)) => { + info!("role_transition complete: {:?}", transition); + } + _ => { + panic!( + "Fullnode TPU/TVU exited for some unexpected reason: {:?}", + status + ); + } + }; } - - exit(1); } diff --git a/src/fullnode.rs b/src/fullnode.rs index c36a8a75ef..38c087dc78 100644 --- a/src/fullnode.rs +++ b/src/fullnode.rs @@ -151,7 +151,6 @@ impl Fullnode { let leader_scheduler = Arc::new(RwLock::new(leader_scheduler)); info!("creating bank..."); - let db_ledger = Self::make_db_ledger(ledger_path); let (bank, entry_height, last_entry_id) = Self::new_bank_from_db_ledger(&db_ledger, leader_scheduler); @@ -167,9 +166,11 @@ impl Fullnode { if let Some(port) = rpc_port { rpc_addr.set_port(port); } + info!("node rpc address: {}", rpc_addr); + info!("node leader_addr: {:?}", leader_addr); let leader_info = leader_addr.map(|i| NodeInfo::new_entry_point(&i)); - let server = Self::new_with_bank( + Self::new_with_bank( keypair, vote_signer, bank, @@ -182,21 +183,7 @@ impl Fullnode { sigverify_disabled, rpc_port, storage_rotate_count, - ); - - match leader_addr { - Some(leader_addr) => { - info!( - "validator ready... rpc address: {}, connected to: {}", - rpc_addr, leader_addr - ); - } - None => { - info!("leader ready... rpc address: {}", rpc_addr); - } - } - - server + ) } /// Create a fullnode instance acting as a leader or validator.