18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -2711,9 +2711,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | ||||
|  | ||||
| [[package]] | ||||
| name = "serde" | ||||
| version = "1.0.106" | ||||
| version = "1.0.110" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" | ||||
| checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" | ||||
| dependencies = [ | ||||
|  "serde_derive", | ||||
| ] | ||||
| @@ -2729,9 +2729,9 @@ dependencies = [ | ||||
|  | ||||
| [[package]] | ||||
| name = "serde_derive" | ||||
| version = "1.0.106" | ||||
| version = "1.0.110" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" | ||||
| checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.12", | ||||
|  "quote 1.0.1", | ||||
| @@ -3290,6 +3290,7 @@ dependencies = [ | ||||
|  "solana-streamer", | ||||
|  "solana-sys-tuner", | ||||
|  "solana-transaction-status", | ||||
|  "solana-version", | ||||
|  "solana-vote-program", | ||||
|  "solana-vote-signer", | ||||
|  "systemstat", | ||||
| @@ -4007,6 +4008,15 @@ dependencies = [ | ||||
|  "solana-vote-signer", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "solana-version" | ||||
| version = "1.1.11" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
|  "serde_derive", | ||||
|  "solana-sdk", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "solana-vest-program" | ||||
| version = "1.1.11" | ||||
|   | ||||
| @@ -58,6 +58,7 @@ members = [ | ||||
|     "transaction-status", | ||||
|     "upload-perf", | ||||
|     "net-utils", | ||||
|     "version", | ||||
|     "vote-signer", | ||||
|     "cli", | ||||
|     "rayon-threadlimit", | ||||
|   | ||||
| @@ -61,6 +61,7 @@ solana-sdk = { path = "../sdk", version = "1.1.11" } | ||||
| solana-stake-program = { path = "../programs/stake", version = "1.1.11" } | ||||
| solana-storage-program = { path = "../programs/storage", version = "1.1.11" } | ||||
| solana-streamer = { path = "../streamer", version = "1.1.11" } | ||||
| solana-version = { path = "../version", version = "1.1.11" } | ||||
| solana-vote-program = { path = "../programs/vote", version = "1.1.11" } | ||||
| solana-vote-signer = { path = "../vote-signer", version = "1.1.11" } | ||||
| solana-sys-tuner = { path = "../sys-tuner", version = "1.1.11" } | ||||
|   | ||||
| @@ -18,8 +18,8 @@ use crate::{ | ||||
|     crds_gossip_error::CrdsGossipError, | ||||
|     crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS}, | ||||
|     crds_value::{ | ||||
|         self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash, Vote, | ||||
|         MAX_WALLCLOCK, | ||||
|         self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash, | ||||
|         Version, Vote, MAX_WALLCLOCK, | ||||
|     }, | ||||
|     epoch_slots::EpochSlots, | ||||
|     result::{Error, Result}, | ||||
| @@ -378,6 +378,7 @@ impl ClusterInfo { | ||||
|                     archivers += 1; | ||||
|                 } | ||||
|  | ||||
|                 let node_version = self.get_node_version(&node.id); | ||||
|                 if my_shred_version != 0 && (node.shred_version != 0 && node.shred_version != my_shred_version) { | ||||
|                     different_shred_nodes += 1; | ||||
|                     None | ||||
| @@ -393,10 +394,9 @@ impl ClusterInfo { | ||||
|                             "none".to_string() | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     let ip_addr = node.gossip.ip(); | ||||
|                     Some(format!( | ||||
|                         "{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n", | ||||
|                         "{:15} {:2}| {:5} | {:44} |{:^15}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n", | ||||
|                         if ContactInfo::is_valid_address(&node.gossip) { | ||||
|                             ip_addr.to_string() | ||||
|                         } else { | ||||
| @@ -405,6 +405,11 @@ impl ClusterInfo { | ||||
|                         if node.id == my_pubkey { "me" } else { "" }.to_string(), | ||||
|                         now.saturating_sub(last_updated), | ||||
|                         node.id.to_string(), | ||||
|                         if let Some(node_version) = node_version { | ||||
|                             node_version.to_string() | ||||
|                         } else { | ||||
|                             "-".to_string() | ||||
|                         }, | ||||
|                         addr_to_string(&ip_addr, &node.gossip), | ||||
|                         addr_to_string(&ip_addr, &node.tpu), | ||||
|                         addr_to_string(&ip_addr, &node.tpu_forwards), | ||||
| @@ -412,7 +417,6 @@ impl ClusterInfo { | ||||
|                         addr_to_string(&ip_addr, &node.tvu_forwards), | ||||
|                         addr_to_string(&ip_addr, &node.repair), | ||||
|                         addr_to_string(&ip_addr, &node.serve_repair), | ||||
|                         addr_to_string(&ip_addr, &node.storage_addr), | ||||
|                         addr_to_string(&ip_addr, &node.rpc), | ||||
|                         addr_to_string(&ip_addr, &node.rpc_pubsub), | ||||
|                         node.shred_version, | ||||
| @@ -423,9 +427,9 @@ impl ClusterInfo { | ||||
|  | ||||
|         format!( | ||||
|             "IP Address        |Age(ms)| Node identifier                              \ | ||||
|              |Gossip| TPU  |TPUfwd| TVU  |TVUfwd|Repair|ServeR|Storag| RPC  |PubSub|ShredVer\n\ | ||||
|              ------------------+-------+----------------------------------------------+\ | ||||
|              ------+------+------+------+------+------+------+------+------+------+--------\n\ | ||||
|              | Version       |Gossip| TPU  |TPUfwd| TVU  |TVUfwd|Repair|ServeR| RPC  |PubSub|ShredVer\n\ | ||||
|              ------------------+-------+----------------------------------------------+---------------+\ | ||||
|              ------+------+------+------+------+------+------+------+------+--------\n\ | ||||
|              {}\ | ||||
|              Nodes: {}{}{}{}", | ||||
|             nodes.join(""), | ||||
| @@ -440,7 +444,7 @@ impl ClusterInfo { | ||||
|             } else { | ||||
|                 "".to_string() | ||||
|             }, | ||||
|             if spy_nodes > 0 { | ||||
|             if different_shred_nodes > 0 { | ||||
|                 format!( | ||||
|                     "\nNodes with different shred version: {}", | ||||
|                     different_shred_nodes | ||||
| @@ -703,6 +707,18 @@ impl ClusterInfo { | ||||
|         (vec, max) | ||||
|     } | ||||
|  | ||||
|     pub fn get_node_version(&self, pubkey: &Pubkey) -> Option<solana_version::Version> { | ||||
|         self.gossip | ||||
|             .read() | ||||
|             .unwrap() | ||||
|             .crds | ||||
|             .table | ||||
|             .get(&CrdsValueLabel::Version(*pubkey)) | ||||
|             .map(|x| x.value.version()) | ||||
|             .flatten() | ||||
|             .map(|version| version.version.clone()) | ||||
|     } | ||||
|  | ||||
|     /// all validators that have a valid rpc port regardless of `shred_version`. | ||||
|     pub fn all_rpc_peers(&self) -> Vec<ContactInfo> { | ||||
|         self.gossip | ||||
| @@ -1313,6 +1329,9 @@ impl ClusterInfo { | ||||
|                 let mut last_contact_info_trace = timestamp(); | ||||
|                 let mut adopt_shred_version = obj.my_shred_version() == 0; | ||||
|                 let recycler = PacketsRecycler::default(); | ||||
|  | ||||
|                 let message = CrdsData::Version(Version::new(obj.id())); | ||||
|                 obj.push_message(CrdsValue::new_signed(message, &obj.keypair)); | ||||
|                 loop { | ||||
|                     let start = timestamp(); | ||||
|                     thread_mem_usage::datapoint("solana-gossip"); | ||||
|   | ||||
| @@ -75,6 +75,7 @@ pub enum CrdsData { | ||||
|     SnapshotHashes(SnapshotHash), | ||||
|     AccountsHashes(SnapshotHash), | ||||
|     EpochSlots(EpochSlotsIndex, EpochSlots), | ||||
|     Version(Version), | ||||
| } | ||||
|  | ||||
| impl Sanitize for CrdsData { | ||||
| @@ -101,6 +102,7 @@ impl Sanitize for CrdsData { | ||||
|                 } | ||||
|                 val.sanitize() | ||||
|             } | ||||
|             CrdsData::Version(version) => version.sanitize(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -206,6 +208,33 @@ impl Vote { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] | ||||
| pub struct Version { | ||||
|     pub from: Pubkey, | ||||
|     pub wallclock: u64, | ||||
|     pub version: solana_version::Version, | ||||
| } | ||||
|  | ||||
| impl Sanitize for Version { | ||||
|     fn sanitize(&self) -> Result<(), SanitizeError> { | ||||
|         if self.wallclock >= MAX_WALLCLOCK { | ||||
|             return Err(SanitizeError::ValueOutOfBounds); | ||||
|         } | ||||
|         self.from.sanitize()?; | ||||
|         self.version.sanitize() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Version { | ||||
|     pub fn new(from: Pubkey) -> Self { | ||||
|         Self { | ||||
|             from, | ||||
|             wallclock: timestamp(), | ||||
|             version: solana_version::Version::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Type of the replicated value | ||||
| /// These are labels for values in a record that is associated with `Pubkey` | ||||
| #[derive(PartialEq, Hash, Eq, Clone, Debug)] | ||||
| @@ -216,6 +245,7 @@ pub enum CrdsValueLabel { | ||||
|     SnapshotHashes(Pubkey), | ||||
|     EpochSlots(EpochSlotsIndex, Pubkey), | ||||
|     AccountsHashes(Pubkey), | ||||
|     Version(Pubkey), | ||||
| } | ||||
|  | ||||
| impl fmt::Display for CrdsValueLabel { | ||||
| @@ -227,6 +257,7 @@ impl fmt::Display for CrdsValueLabel { | ||||
|             CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()), | ||||
|             CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()), | ||||
|             CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", self.pubkey()), | ||||
|             CrdsValueLabel::Version(_) => write!(f, "Version({})", self.pubkey()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -240,6 +271,7 @@ impl CrdsValueLabel { | ||||
|             CrdsValueLabel::SnapshotHashes(p) => *p, | ||||
|             CrdsValueLabel::EpochSlots(_, p) => *p, | ||||
|             CrdsValueLabel::AccountsHashes(p) => *p, | ||||
|             CrdsValueLabel::Version(p) => *p, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -257,7 +289,7 @@ impl CrdsValue { | ||||
|         value.sign(keypair); | ||||
|         value | ||||
|     } | ||||
|     /// Totally unsecure unverfiable wallclock of the node that generated this message | ||||
|     /// Totally unsecure unverifiable wallclock of the node that generated this message | ||||
|     /// Latest wallclock is always picked. | ||||
|     /// This is used to time out push messages. | ||||
|     pub fn wallclock(&self) -> u64 { | ||||
| @@ -268,6 +300,7 @@ impl CrdsValue { | ||||
|             CrdsData::SnapshotHashes(hash) => hash.wallclock, | ||||
|             CrdsData::AccountsHashes(hash) => hash.wallclock, | ||||
|             CrdsData::EpochSlots(_, p) => p.wallclock, | ||||
|             CrdsData::Version(version) => version.wallclock, | ||||
|         } | ||||
|     } | ||||
|     pub fn pubkey(&self) -> Pubkey { | ||||
| @@ -278,6 +311,7 @@ impl CrdsValue { | ||||
|             CrdsData::SnapshotHashes(hash) => hash.from, | ||||
|             CrdsData::AccountsHashes(hash) => hash.from, | ||||
|             CrdsData::EpochSlots(_, p) => p.from, | ||||
|             CrdsData::Version(version) => version.from, | ||||
|         } | ||||
|     } | ||||
|     pub fn label(&self) -> CrdsValueLabel { | ||||
| @@ -288,6 +322,7 @@ impl CrdsValue { | ||||
|             CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()), | ||||
|             CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()), | ||||
|             CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()), | ||||
|             CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()), | ||||
|         } | ||||
|     } | ||||
|     pub fn contact_info(&self) -> Option<&ContactInfo> { | ||||
| @@ -338,6 +373,13 @@ impl CrdsValue { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn version(&self) -> Option<&Version> { | ||||
|         match &self.data { | ||||
|             CrdsData::Version(version) => Some(version), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Return all the possible labels for a record identified by Pubkey. | ||||
|     pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> { | ||||
|         let mut labels = vec![ | ||||
| @@ -345,6 +387,7 @@ impl CrdsValue { | ||||
|             CrdsValueLabel::LowestSlot(*key), | ||||
|             CrdsValueLabel::SnapshotHashes(*key), | ||||
|             CrdsValueLabel::AccountsHashes(*key), | ||||
|             CrdsValueLabel::Version(*key), | ||||
|         ]; | ||||
|         labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key))); | ||||
|         labels.extend((0..MAX_EPOCH_SLOTS).map(|ix| CrdsValueLabel::EpochSlots(ix, *key))); | ||||
| @@ -395,7 +438,7 @@ mod test { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_labels() { | ||||
|         let mut hits = [false; 4 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize]; | ||||
|         let mut hits = [false; 5 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize]; | ||||
|         // this method should cover all the possible labels | ||||
|         for v in &CrdsValue::record_labels(&Pubkey::default()) { | ||||
|             match v { | ||||
| @@ -403,9 +446,10 @@ mod test { | ||||
|                 CrdsValueLabel::LowestSlot(_) => hits[1] = true, | ||||
|                 CrdsValueLabel::SnapshotHashes(_) => hits[2] = true, | ||||
|                 CrdsValueLabel::AccountsHashes(_) => hits[3] = true, | ||||
|                 CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 4] = true, | ||||
|                 CrdsValueLabel::Version(_) => hits[4] = true, | ||||
|                 CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 5] = true, | ||||
|                 CrdsValueLabel::EpochSlots(ix, _) => { | ||||
|                     hits[*ix as usize + MAX_VOTES as usize + 4] = true | ||||
|                     hits[*ix as usize + MAX_VOTES as usize + 5] = true | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1474,7 +1474,7 @@ impl RpcSol for RpcSolImpl { | ||||
|  | ||||
|     fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> { | ||||
|         Ok(RpcVersionInfo { | ||||
|             solana_core: solana_clap_utils::version!().to_string(), | ||||
|             solana_core: solana_version::Version::default().to_string(), | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -2637,7 +2637,7 @@ pub mod tests { | ||||
|         let expected = json!({ | ||||
|             "jsonrpc": "2.0", | ||||
|             "result": { | ||||
|                 "solana-core": solana_clap_utils::version!().to_string() | ||||
|                 "solana-core": solana_version::version!().to_string() | ||||
|             }, | ||||
|             "id": 1 | ||||
|         }); | ||||
|   | ||||
| @@ -46,7 +46,7 @@ fn test_rpc_client() { | ||||
|  | ||||
|     assert_eq!( | ||||
|         client.get_version().unwrap().solana_core, | ||||
|         solana_clap_utils::version!() | ||||
|         solana_version::version!() | ||||
|     ); | ||||
|  | ||||
|     assert!(client.get_account(&bob_pubkey).is_err()); | ||||
|   | ||||
							
								
								
									
										2
									
								
								version/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								version/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| /target/ | ||||
| /farf/ | ||||
							
								
								
									
										20
									
								
								version/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								version/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| [package] | ||||
| name = "solana-version" | ||||
| version = "1.1.11" | ||||
| description = "Solana Version" | ||||
| authors = ["Solana Maintainers <maintainers@solana.com>"] | ||||
| repository = "https://github.com/solana-labs/solana" | ||||
| license = "Apache-2.0" | ||||
| homepage = "https://solana.com/" | ||||
| edition = "2018" | ||||
|  | ||||
| [dependencies] | ||||
| serde = "1.0.105" | ||||
| serde_derive = "1.0.103" | ||||
| solana-sdk = { path = "../sdk", version = "1.1.11" } | ||||
|  | ||||
| [lib] | ||||
| name = "solana_version" | ||||
|  | ||||
| [package.metadata.docs.rs] | ||||
| targets = ["x86_64-unknown-linux-gnu"] | ||||
							
								
								
									
										49
									
								
								version/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								version/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| extern crate serde_derive; | ||||
| use serde_derive::{Deserialize, Serialize}; | ||||
| use solana_sdk::sanitize::Sanitize; | ||||
| use std::fmt; | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] | ||||
| pub struct Version { | ||||
|     major: u16, | ||||
|     minor: u16, | ||||
|     patch: u16, | ||||
|     commit: Option<u32>, // first 4 bytes of the sha1 commit hash | ||||
| } | ||||
|  | ||||
| impl Default for Version { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(), | ||||
|             minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(), | ||||
|             patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(), | ||||
|             commit: option_env!("CI_COMMIT") | ||||
|                 .map(|sha1| u32::from_str_radix(&sha1[..8], 16).unwrap()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for Version { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         write!( | ||||
|             f, | ||||
|             "{}.{}.{} {}", | ||||
|             self.major, | ||||
|             self.minor, | ||||
|             self.patch, | ||||
|             match self.commit { | ||||
|                 None => "devbuild".to_string(), | ||||
|                 Some(commit) => format!("{:08x}", commit), | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Sanitize for Version {} | ||||
|  | ||||
| #[macro_export] | ||||
| macro_rules! version { | ||||
|     () => { | ||||
|         &*format!("{}", $crate::Version::default()) | ||||
|     }; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user