From bf15cad36b6755d136deece6767a55d068a3f107 Mon Sep 17 00:00:00 2001 From: Pankaj Garg Date: Mon, 13 Aug 2018 08:55:13 -0700 Subject: [PATCH] Add get_finality request and use it from multinode test (#941) --- src/bank.rs | 21 +++++++++++++++++++++ src/request.rs | 2 ++ src/request_processor.rs | 6 ++++++ src/thin_client.rs | 33 +++++++++++++++++++++++++++++++++ src/vote_stage.rs | 2 ++ tests/multinode.rs | 11 +++++++++-- 6 files changed, 73 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/bank.rs mode change 100644 => 100755 src/request.rs mode change 100644 => 100755 src/request_processor.rs mode change 100644 => 100755 src/thin_client.rs mode change 100644 => 100755 src/vote_stage.rs diff --git a/src/bank.rs b/src/bank.rs old mode 100644 new mode 100755 index 5aa4e18df..b24008cc8 --- a/src/bank.rs +++ b/src/bank.rs @@ -15,6 +15,7 @@ use log::Level; use mint::Mint; use payment_plan::{Payment, PaymentPlan, Witness}; use signature::{Keypair, Pubkey, Signature}; +use std; use std::collections::hash_map::Entry::Occupied; use std::collections::{HashMap, HashSet, VecDeque}; use std::result; @@ -91,6 +92,9 @@ pub struct Bank { /// This bool allows us to submit metrics that are specific for leaders or validators /// It is set to `true` by fullnode before creating the bank. pub is_leader: bool, + + // The latest finality time for the network + finality_time: AtomicUsize, } impl Default for Bank { @@ -102,6 +106,7 @@ impl Default for Bank { last_ids_sigs: RwLock::new(HashMap::new()), transaction_count: AtomicUsize::new(0), is_leader: true, + finality_time: AtomicUsize::new(std::usize::MAX), } } } @@ -582,6 +587,14 @@ impl Bank { } false } + + pub fn finality(&self) -> usize { + self.finality_time.load(Ordering::Relaxed) + } + + pub fn set_finality(&self, finality: usize) { + self.finality_time.store(finality, Ordering::Relaxed); + } } #[cfg(test)] @@ -595,6 +608,7 @@ mod tests { use ledger; use packet::BLOB_DATA_SIZE; use signature::KeypairUtil; + use std; use std::io::{BufReader, Cursor, Seek, SeekFrom}; use std::mem::size_of; @@ -982,5 +996,12 @@ mod tests { let validator_bank = Bank::new_default(false); assert!(!validator_bank.is_leader); } + #[test] + fn test_finality() { + let def_bank = Bank::default(); + assert_eq!(def_bank.finality(), std::usize::MAX); + def_bank.set_finality(90); + assert_eq!(def_bank.finality(), 90); + } } diff --git a/src/request.rs b/src/request.rs old mode 100644 new mode 100755 index 50ccddf16..757431b36 --- a/src/request.rs +++ b/src/request.rs @@ -10,6 +10,7 @@ pub enum Request { GetLastId, GetTransactionCount, GetSignature { signature: Signature }, + GetFinality, } impl Request { @@ -25,4 +26,5 @@ pub enum Response { LastId { id: Hash }, TransactionCount { transaction_count: u64 }, SignatureStatus { signature_status: bool }, + Finality { time: usize }, } diff --git a/src/request_processor.rs b/src/request_processor.rs old mode 100644 new mode 100755 index f55bdf37e..80be2f91e --- a/src/request_processor.rs +++ b/src/request_processor.rs @@ -46,6 +46,12 @@ impl RequestProcessor { info!("Response::Signature {:?}", rsp); Some(rsp) } + Request::GetFinality => { + let time = self.bank.finality(); + let rsp = (Response::Finality { time }, rsp_addr); + info!("Response::Finality {:?}", rsp); + Some(rsp) + } } } diff --git a/src/thin_client.rs b/src/thin_client.rs old mode 100644 new mode 100755 index 502365266..689129fc9 --- a/src/thin_client.rs +++ b/src/thin_client.rs @@ -29,6 +29,7 @@ pub struct ThinClient { transaction_count: u64, balances: HashMap, signature_status: bool, + finality: Option, } impl ThinClient { @@ -50,6 +51,7 @@ impl ThinClient { transaction_count: 0, balances: HashMap::new(), signature_status: false, + finality: None, } } @@ -83,6 +85,10 @@ impl ThinClient { trace!("Response signature not found"); } } + Response::Finality { time } => { + trace!("Response finality {:?}", time); + self.finality = Some(time); + } } } @@ -143,6 +149,33 @@ impl ThinClient { .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "nokey")) } + /// Request the finality from the leader node + pub fn get_finality(&mut self) -> usize { + trace!("get_finality"); + let req = Request::GetFinality; + let data = serialize(&req).expect("serialize GetFinality in pub fn get_finality"); + let mut done = false; + while !done { + debug!("get_finality send_to {}", &self.requests_addr); + self.requests_socket + .send_to(&data, &self.requests_addr) + .expect("buffer error in pub fn get_finality"); + + match self.recv_response() { + Ok(resp) => { + if let Response::Finality { .. } = resp { + done = true; + } + self.process_response(&resp); + } + Err(e) => { + debug!("thin_client get_finality error: {}", e); + } + } + } + self.finality.expect("some finality") + } + /// Request the transaction count. If the response packet is dropped by the network, /// this method will hang. pub fn transaction_count(&mut self) -> u64 { diff --git a/src/vote_stage.rs b/src/vote_stage.rs old mode 100644 new mode 100755 index 223bbc7c3..ec0e63fb1 --- a/src/vote_stage.rs +++ b/src/vote_stage.rs @@ -152,6 +152,8 @@ pub fn send_leader_vote( ); inc_new_counter_info!("vote_stage-leader_sent_vote", 1); + bank.set_finality((now - *last_valid_validator_timestamp) as usize); + metrics::submit( influxdb::Point::new(&"leader-finality") .add_field("duration_ms", influxdb::Value::Integer(finality_ms as i64)) diff --git a/tests/multinode.rs b/tests/multinode.rs index a193f5f82..439d8f90e 100755 --- a/tests/multinode.rs +++ b/tests/multinode.rs @@ -695,12 +695,13 @@ fn test_multi_node_dynamic_network() { info!("{} nodes are lagging behind leader", num_nodes_behind); } info!( - "SUCCESS[{}] {} out of {} distance: {} max_distance: {}", + "SUCCESS[{}] {} out of {} distance: {} max_distance: {} finality: {}", i, success, validators.len(), total_distance, - max_distance + max_distance, + get_finality(&leader_data) ); if success == validators.len() && total_distance == 0 { consecutive_success += 1; @@ -820,3 +821,9 @@ fn retry_send_tx_and_retry_get_balance( } None } + +fn get_finality(leader: &NodeInfo) -> usize { + let mut client = mk_client(leader); + trace!("getting leader finality"); + client.get_finality() +}