Add feature set identifier to gossiped version information
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4685,6 +4685,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-logger 1.4.0",
|
"solana-logger 1.4.0",
|
||||||
|
"solana-runtime",
|
||||||
"solana-sdk 1.4.0",
|
"solana-sdk 1.4.0",
|
||||||
"solana-sdk-macro-frozen-abi 1.4.0",
|
"solana-sdk-macro-frozen-abi 1.4.0",
|
||||||
]
|
]
|
||||||
|
@ -17,7 +17,7 @@ use solana_client::{
|
|||||||
pubsub_client::PubsubClient,
|
pubsub_client::PubsubClient,
|
||||||
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
||||||
rpc_config::{RpcLargestAccountsConfig, RpcLargestAccountsFilter},
|
rpc_config::{RpcLargestAccountsConfig, RpcLargestAccountsFilter},
|
||||||
rpc_response::{RpcVersionInfo, SlotInfo},
|
rpc_response::SlotInfo,
|
||||||
};
|
};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -1314,12 +1314,9 @@ pub fn process_show_validators(
|
|||||||
for contact_info in rpc_client.get_cluster_nodes()? {
|
for contact_info in rpc_client.get_cluster_nodes()? {
|
||||||
node_version.insert(
|
node_version.insert(
|
||||||
contact_info.pubkey,
|
contact_info.pubkey,
|
||||||
RpcVersionInfo {
|
contact_info
|
||||||
solana_core: contact_info
|
.version
|
||||||
.version
|
.unwrap_or_else(|| unknown_version.clone()),
|
||||||
.unwrap_or_else(|| unknown_version.clone()),
|
|
||||||
}
|
|
||||||
.to_string(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +121,7 @@ pub enum ReceivedSignatureResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcContactInfo {
|
pub struct RpcContactInfo {
|
||||||
/// Pubkey of the node as a base-58 string
|
/// Pubkey of the node as a base-58 string
|
||||||
pub pubkey: String,
|
pub pubkey: String,
|
||||||
@ -132,6 +133,8 @@ pub struct RpcContactInfo {
|
|||||||
pub rpc: Option<SocketAddr>,
|
pub rpc: Option<SocketAddr>,
|
||||||
/// Software version
|
/// Software version
|
||||||
pub version: Option<String>,
|
pub version: Option<String>,
|
||||||
|
/// First 4 bytes of the FeatureSet identifier
|
||||||
|
pub feature_set: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||||
@ -142,6 +145,8 @@ pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
|
|||||||
pub struct RpcVersionInfo {
|
pub struct RpcVersionInfo {
|
||||||
/// The current version of solana-core
|
/// The current version of solana-core
|
||||||
pub solana_core: String,
|
pub solana_core: String,
|
||||||
|
/// first 4 bytes of the FeatureSet identifier
|
||||||
|
pub feature_set: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for RpcVersionInfo {
|
impl fmt::Debug for RpcVersionInfo {
|
||||||
|
@ -359,7 +359,7 @@ pub fn make_accounts_hashes_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO These messages should go through the gpu pipeline for spam filtering
|
// TODO These messages should go through the gpu pipeline for spam filtering
|
||||||
#[frozen_abi(digest = "CnN1gW2K2TRydGc84eYnQJwdTADPjQf6LJLZ4RP1QeoH")]
|
#[frozen_abi(digest = "3ZHQscZ9SgxKh45idzHv3hiagyyPRtDgeySmJn171PTi")]
|
||||||
#[derive(Serialize, Deserialize, Debug, AbiEnumVisitor, AbiExample)]
|
#[derive(Serialize, Deserialize, Debug, AbiEnumVisitor, AbiExample)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum Protocol {
|
enum Protocol {
|
||||||
@ -573,7 +573,7 @@ impl ClusterInfo {
|
|||||||
}
|
}
|
||||||
let ip_addr = node.gossip.ip();
|
let ip_addr = node.gossip.ip();
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"{:15} {:2}| {:5} | {:44} |{:^15}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n",
|
"{:15} {:2}| {:5} | {:44} |{:^9}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n",
|
||||||
if ContactInfo::is_valid_address(&node.gossip) {
|
if ContactInfo::is_valid_address(&node.gossip) {
|
||||||
ip_addr.to_string()
|
ip_addr.to_string()
|
||||||
} else {
|
} else {
|
||||||
@ -605,8 +605,8 @@ impl ClusterInfo {
|
|||||||
|
|
||||||
format!(
|
format!(
|
||||||
"IP Address |Age(ms)| Node identifier \
|
"IP Address |Age(ms)| Node identifier \
|
||||||
| Version |Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR| RPC |PubSub|ShredVer\n\
|
| Version |Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR| RPC |PubSub|ShredVer\n\
|
||||||
------------------+-------+----------------------------------------------+---------------+\
|
------------------+-------+----------------------------------------------+---------+\
|
||||||
------+------+------+------+------+------+------+------+------+--------\n\
|
------+------+------+------+------+------+------+------+------+--------\n\
|
||||||
{}\
|
{}\
|
||||||
Nodes: {}{}{}",
|
Nodes: {}{}{}",
|
||||||
@ -894,7 +894,8 @@ impl ClusterInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_node_version(&self, pubkey: &Pubkey) -> Option<solana_version::Version> {
|
pub fn get_node_version(&self, pubkey: &Pubkey) -> Option<solana_version::Version> {
|
||||||
self.gossip
|
let version = self
|
||||||
|
.gossip
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.crds
|
.crds
|
||||||
@ -902,7 +903,21 @@ impl ClusterInfo {
|
|||||||
.get(&CrdsValueLabel::Version(*pubkey))
|
.get(&CrdsValueLabel::Version(*pubkey))
|
||||||
.map(|x| x.value.version())
|
.map(|x| x.value.version())
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|version| version.version.clone())
|
.map(|version| version.version.clone());
|
||||||
|
|
||||||
|
if version.is_none() {
|
||||||
|
self.gossip
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.crds
|
||||||
|
.table
|
||||||
|
.get(&CrdsValueLabel::LegacyVersion(*pubkey))
|
||||||
|
.map(|x| x.value.legacy_version())
|
||||||
|
.flatten()
|
||||||
|
.map(|version| version.version.clone().into())
|
||||||
|
} else {
|
||||||
|
version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// all validators that have a valid rpc port regardless of `shred_version`.
|
/// all validators that have a valid rpc port regardless of `shred_version`.
|
||||||
|
@ -75,6 +75,7 @@ pub enum CrdsData {
|
|||||||
SnapshotHashes(SnapshotHash),
|
SnapshotHashes(SnapshotHash),
|
||||||
AccountsHashes(SnapshotHash),
|
AccountsHashes(SnapshotHash),
|
||||||
EpochSlots(EpochSlotsIndex, EpochSlots),
|
EpochSlots(EpochSlotsIndex, EpochSlots),
|
||||||
|
LegacyVersion(LegacyVersion),
|
||||||
Version(Version),
|
Version(Version),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +103,7 @@ impl Sanitize for CrdsData {
|
|||||||
}
|
}
|
||||||
val.sanitize()
|
val.sanitize()
|
||||||
}
|
}
|
||||||
|
CrdsData::LegacyVersion(version) => version.sanitize(),
|
||||||
CrdsData::Version(version) => version.sanitize(),
|
CrdsData::Version(version) => version.sanitize(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,6 +210,23 @@ impl Vote {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, AbiExample)]
|
||||||
|
pub struct LegacyVersion {
|
||||||
|
pub from: Pubkey,
|
||||||
|
pub wallclock: u64,
|
||||||
|
pub version: solana_version::LegacyVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sanitize for LegacyVersion {
|
||||||
|
fn sanitize(&self) -> Result<(), SanitizeError> {
|
||||||
|
if self.wallclock >= MAX_WALLCLOCK {
|
||||||
|
return Err(SanitizeError::ValueOutOfBounds);
|
||||||
|
}
|
||||||
|
self.from.sanitize()?;
|
||||||
|
self.version.sanitize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, AbiExample)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, AbiExample)]
|
||||||
pub struct Version {
|
pub struct Version {
|
||||||
pub from: Pubkey,
|
pub from: Pubkey,
|
||||||
@ -245,6 +264,7 @@ pub enum CrdsValueLabel {
|
|||||||
SnapshotHashes(Pubkey),
|
SnapshotHashes(Pubkey),
|
||||||
EpochSlots(EpochSlotsIndex, Pubkey),
|
EpochSlots(EpochSlotsIndex, Pubkey),
|
||||||
AccountsHashes(Pubkey),
|
AccountsHashes(Pubkey),
|
||||||
|
LegacyVersion(Pubkey),
|
||||||
Version(Pubkey),
|
Version(Pubkey),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +277,7 @@ impl fmt::Display for CrdsValueLabel {
|
|||||||
CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()),
|
CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()),
|
||||||
CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()),
|
CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()),
|
||||||
CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", self.pubkey()),
|
CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", self.pubkey()),
|
||||||
|
CrdsValueLabel::LegacyVersion(_) => write!(f, "LegacyVersion({})", self.pubkey()),
|
||||||
CrdsValueLabel::Version(_) => write!(f, "Version({})", self.pubkey()),
|
CrdsValueLabel::Version(_) => write!(f, "Version({})", self.pubkey()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,6 +292,7 @@ impl CrdsValueLabel {
|
|||||||
CrdsValueLabel::SnapshotHashes(p) => *p,
|
CrdsValueLabel::SnapshotHashes(p) => *p,
|
||||||
CrdsValueLabel::EpochSlots(_, p) => *p,
|
CrdsValueLabel::EpochSlots(_, p) => *p,
|
||||||
CrdsValueLabel::AccountsHashes(p) => *p,
|
CrdsValueLabel::AccountsHashes(p) => *p,
|
||||||
|
CrdsValueLabel::LegacyVersion(p) => *p,
|
||||||
CrdsValueLabel::Version(p) => *p,
|
CrdsValueLabel::Version(p) => *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,6 +322,7 @@ impl CrdsValue {
|
|||||||
CrdsData::SnapshotHashes(hash) => hash.wallclock,
|
CrdsData::SnapshotHashes(hash) => hash.wallclock,
|
||||||
CrdsData::AccountsHashes(hash) => hash.wallclock,
|
CrdsData::AccountsHashes(hash) => hash.wallclock,
|
||||||
CrdsData::EpochSlots(_, p) => p.wallclock,
|
CrdsData::EpochSlots(_, p) => p.wallclock,
|
||||||
|
CrdsData::LegacyVersion(version) => version.wallclock,
|
||||||
CrdsData::Version(version) => version.wallclock,
|
CrdsData::Version(version) => version.wallclock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,6 +334,7 @@ impl CrdsValue {
|
|||||||
CrdsData::SnapshotHashes(hash) => hash.from,
|
CrdsData::SnapshotHashes(hash) => hash.from,
|
||||||
CrdsData::AccountsHashes(hash) => hash.from,
|
CrdsData::AccountsHashes(hash) => hash.from,
|
||||||
CrdsData::EpochSlots(_, p) => p.from,
|
CrdsData::EpochSlots(_, p) => p.from,
|
||||||
|
CrdsData::LegacyVersion(version) => version.from,
|
||||||
CrdsData::Version(version) => version.from,
|
CrdsData::Version(version) => version.from,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,6 +346,7 @@ impl CrdsValue {
|
|||||||
CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()),
|
CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()),
|
||||||
CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()),
|
CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()),
|
||||||
CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()),
|
CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()),
|
||||||
|
CrdsData::LegacyVersion(_) => CrdsValueLabel::LegacyVersion(self.pubkey()),
|
||||||
CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()),
|
CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,6 +398,13 @@ impl CrdsValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn legacy_version(&self) -> Option<&LegacyVersion> {
|
||||||
|
match &self.data {
|
||||||
|
CrdsData::LegacyVersion(legacy_version) => Some(legacy_version),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version(&self) -> Option<&Version> {
|
pub fn version(&self) -> Option<&Version> {
|
||||||
match &self.data {
|
match &self.data {
|
||||||
CrdsData::Version(version) => Some(version),
|
CrdsData::Version(version) => Some(version),
|
||||||
@ -387,6 +419,7 @@ impl CrdsValue {
|
|||||||
CrdsValueLabel::LowestSlot(*key),
|
CrdsValueLabel::LowestSlot(*key),
|
||||||
CrdsValueLabel::SnapshotHashes(*key),
|
CrdsValueLabel::SnapshotHashes(*key),
|
||||||
CrdsValueLabel::AccountsHashes(*key),
|
CrdsValueLabel::AccountsHashes(*key),
|
||||||
|
CrdsValueLabel::LegacyVersion(*key),
|
||||||
CrdsValueLabel::Version(*key),
|
CrdsValueLabel::Version(*key),
|
||||||
];
|
];
|
||||||
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
|
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
|
||||||
@ -438,7 +471,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_labels() {
|
fn test_labels() {
|
||||||
let mut hits = [false; 5 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize];
|
let mut hits = [false; 6 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize];
|
||||||
// this method should cover all the possible labels
|
// this method should cover all the possible labels
|
||||||
for v in &CrdsValue::record_labels(&Pubkey::default()) {
|
for v in &CrdsValue::record_labels(&Pubkey::default()) {
|
||||||
match v {
|
match v {
|
||||||
@ -446,10 +479,11 @@ mod test {
|
|||||||
CrdsValueLabel::LowestSlot(_) => hits[1] = true,
|
CrdsValueLabel::LowestSlot(_) => hits[1] = true,
|
||||||
CrdsValueLabel::SnapshotHashes(_) => hits[2] = true,
|
CrdsValueLabel::SnapshotHashes(_) => hits[2] = true,
|
||||||
CrdsValueLabel::AccountsHashes(_) => hits[3] = true,
|
CrdsValueLabel::AccountsHashes(_) => hits[3] = true,
|
||||||
CrdsValueLabel::Version(_) => hits[4] = true,
|
CrdsValueLabel::LegacyVersion(_) => hits[4] = true,
|
||||||
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 5] = true,
|
CrdsValueLabel::Version(_) => hits[5] = true,
|
||||||
|
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 6] = true,
|
||||||
CrdsValueLabel::EpochSlots(ix, _) => {
|
CrdsValueLabel::EpochSlots(ix, _) => {
|
||||||
hits[*ix as usize + MAX_VOTES as usize + 5] = true
|
hits[*ix as usize + MAX_VOTES as usize + 6] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1945,14 +1945,19 @@ impl RpcSol for RpcSolImpl {
|
|||||||
if my_shred_version == contact_info.shred_version
|
if my_shred_version == contact_info.shred_version
|
||||||
&& ContactInfo::is_valid_address(&contact_info.gossip)
|
&& ContactInfo::is_valid_address(&contact_info.gossip)
|
||||||
{
|
{
|
||||||
|
let (version, feature_set) =
|
||||||
|
if let Some(version) = cluster_info.get_node_version(&contact_info.id) {
|
||||||
|
(Some(version.to_string()), Some(version.feature_set))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
Some(RpcContactInfo {
|
Some(RpcContactInfo {
|
||||||
pubkey: contact_info.id.to_string(),
|
pubkey: contact_info.id.to_string(),
|
||||||
gossip: Some(contact_info.gossip),
|
gossip: Some(contact_info.gossip),
|
||||||
tpu: valid_address_or_none(&contact_info.tpu),
|
tpu: valid_address_or_none(&contact_info.tpu),
|
||||||
rpc: valid_address_or_none(&contact_info.rpc),
|
rpc: valid_address_or_none(&contact_info.rpc),
|
||||||
version: cluster_info
|
version,
|
||||||
.get_node_version(&contact_info.id)
|
feature_set,
|
||||||
.map(|v| v.to_string()),
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None // Exclude spy nodes
|
None // Exclude spy nodes
|
||||||
@ -2299,8 +2304,10 @@ impl RpcSol for RpcSolImpl {
|
|||||||
|
|
||||||
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
||||||
debug!("get_version rpc request received");
|
debug!("get_version rpc request received");
|
||||||
|
let version = solana_version::Version::default();
|
||||||
Ok(RpcVersionInfo {
|
Ok(RpcVersionInfo {
|
||||||
solana_core: solana_version::Version::default().to_string(),
|
solana_core: version.to_string(),
|
||||||
|
feature_set: Some(version.feature_set),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2843,7 +2850,7 @@ pub mod tests {
|
|||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
let expected = format!(
|
let expected = format!(
|
||||||
r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:{}", "version": null}}],"id":1}}"#,
|
r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:{}", "version": null, "featureSet": null}}],"id":1}}"#,
|
||||||
leader_pubkey,
|
leader_pubkey,
|
||||||
rpc_port::DEFAULT_RPC_PORT
|
rpc_port::DEFAULT_RPC_PORT
|
||||||
);
|
);
|
||||||
@ -4394,10 +4401,12 @@ pub mod tests {
|
|||||||
|
|
||||||
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getVersion"}"#;
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getVersion"}"#;
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta);
|
||||||
|
let version = solana_version::Version::default();
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"solana-core": solana_version::version!().to_string()
|
"solana-core": version.to_string(),
|
||||||
|
"feature-set": version.feature_set,
|
||||||
},
|
},
|
||||||
"id": 1
|
"id": 1
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,7 @@ serde = "1.0.112"
|
|||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
solana-logger = { path = "../logger", version = "1.4.0" }
|
solana-logger = { path = "../logger", version = "1.4.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.4.0" }
|
solana-sdk = { path = "../sdk", version = "1.4.0" }
|
||||||
|
solana-runtime = { path = "../runtime", version = "1.4.0" }
|
||||||
solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "1.4.0" }
|
solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "1.4.0" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -3,19 +3,42 @@
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use solana_sdk::sanitize::Sanitize;
|
use solana_sdk::sanitize::Sanitize;
|
||||||
use std::fmt;
|
use std::{convert::TryInto, fmt};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate solana_sdk_macro_frozen_abi;
|
extern crate solana_sdk_macro_frozen_abi;
|
||||||
|
|
||||||
|
// Older version structure used by 1.3.12 and earlier releases
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, AbiExample)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, AbiExample)]
|
||||||
pub struct Version {
|
pub struct LegacyVersion {
|
||||||
major: u16,
|
major: u16,
|
||||||
minor: u16,
|
minor: u16,
|
||||||
patch: u16,
|
patch: u16,
|
||||||
commit: Option<u32>, // first 4 bytes of the sha1 commit hash
|
commit: Option<u32>, // first 4 bytes of the sha1 commit hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sanitize for LegacyVersion {}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, PartialEq, AbiExample)]
|
||||||
|
pub struct Version {
|
||||||
|
pub major: u16,
|
||||||
|
pub minor: u16,
|
||||||
|
pub patch: u16,
|
||||||
|
pub commit: Option<u32>, // first 4 bytes of the sha1 commit hash
|
||||||
|
pub feature_set: u32, // first 4 bytes of the FeatureSet identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LegacyVersion> for Version {
|
||||||
|
fn from(legacy_version: LegacyVersion) -> Self {
|
||||||
|
Self {
|
||||||
|
major: legacy_version.major,
|
||||||
|
minor: legacy_version.minor,
|
||||||
|
patch: legacy_version.patch,
|
||||||
|
commit: legacy_version.commit,
|
||||||
|
feature_set: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
|
fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
|
||||||
let sha1 = sha1?;
|
let sha1 = sha1?;
|
||||||
if sha1.len() < 8 {
|
if sha1.len() < 8 {
|
||||||
@ -27,27 +50,42 @@ fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
|
|||||||
|
|
||||||
impl Default for Version {
|
impl Default for Version {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let feature_set = u32::from_le_bytes(
|
||||||
|
solana_runtime::feature_set::FeatureSet::default()
|
||||||
|
.id
|
||||||
|
.as_ref()[..4]
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
Self {
|
Self {
|
||||||
major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
|
major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
|
||||||
minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
|
minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
|
||||||
patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
|
patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
|
||||||
commit: compute_commit(option_env!("CI_COMMIT")),
|
commit: compute_commit(option_env!("CI_COMMIT")),
|
||||||
|
feature_set,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Version {
|
impl fmt::Display for Version {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}.{}.{}", self.major, self.minor, self.patch,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Version {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}.{}.{} {}",
|
"{}.{}.{} (src:{}; feat:{})",
|
||||||
self.major,
|
self.major,
|
||||||
self.minor,
|
self.minor,
|
||||||
self.patch,
|
self.patch,
|
||||||
match self.commit {
|
match self.commit {
|
||||||
None => "devbuild".to_string(),
|
None => "devbuild".to_string(),
|
||||||
Some(commit) => format!("{:08x}", commit),
|
Some(commit) => format!("{:08x}", commit),
|
||||||
}
|
},
|
||||||
|
self.feature_set,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user