2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
parse_account_data::{ParsableAccount, ParseAccountError},
|
|
|
|
validator_info,
|
|
|
|
},
|
|
|
|
bincode::deserialize,
|
|
|
|
serde_json::Value,
|
|
|
|
solana_config_program::{get_config_data, ConfigKeys},
|
|
|
|
solana_sdk::{
|
|
|
|
pubkey::Pubkey,
|
|
|
|
stake::config::{self as stake_config, Config as StakeConfig},
|
|
|
|
},
|
2020-08-09 00:50:45 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
|
2021-06-15 09:04:00 -07:00
|
|
|
let parsed_account = if pubkey == &stake_config::id() {
|
2020-08-09 00:50:45 -07:00
|
|
|
get_config_data(data)
|
|
|
|
.ok()
|
|
|
|
.and_then(|data| deserialize::<StakeConfig>(data).ok())
|
|
|
|
.map(|config| ConfigAccountType::StakeConfig(config.into()))
|
|
|
|
} else {
|
|
|
|
deserialize::<ConfigKeys>(data).ok().and_then(|key_list| {
|
|
|
|
if !key_list.keys.is_empty() && key_list.keys[0].0 == validator_info::id() {
|
|
|
|
parse_config_data::<String>(data, key_list.keys).and_then(|validator_info| {
|
|
|
|
Some(ConfigAccountType::ValidatorInfo(UiConfig {
|
|
|
|
keys: validator_info.keys,
|
|
|
|
config_data: serde_json::from_str(&validator_info.config_data).ok()?,
|
|
|
|
}))
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
parsed_account.ok_or(ParseAccountError::AccountNotParsable(
|
|
|
|
ParsableAccount::Config,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_config_data<T>(data: &[u8], keys: Vec<(Pubkey, bool)>) -> Option<UiConfig<T>>
|
|
|
|
where
|
|
|
|
T: serde::de::DeserializeOwned,
|
|
|
|
{
|
2021-06-18 06:34:46 -07:00
|
|
|
let config_data: T = deserialize(get_config_data(data).ok()?).ok()?;
|
2020-08-09 00:50:45 -07:00
|
|
|
let keys = keys
|
|
|
|
.iter()
|
|
|
|
.map(|key| UiConfigKey {
|
|
|
|
pubkey: key.0.to_string(),
|
|
|
|
signer: key.1,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
Some(UiConfig { keys, config_data })
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
#[serde(rename_all = "camelCase", tag = "type", content = "info")]
|
|
|
|
pub enum ConfigAccountType {
|
|
|
|
StakeConfig(UiStakeConfig),
|
|
|
|
ValidatorInfo(UiConfig<Value>),
|
|
|
|
}
|
|
|
|
|
2022-05-22 18:00:42 -07:00
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
2020-08-09 00:50:45 -07:00
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct UiConfigKey {
|
|
|
|
pub pubkey: String,
|
|
|
|
pub signer: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct UiStakeConfig {
|
|
|
|
pub warmup_cooldown_rate: f64,
|
|
|
|
pub slash_penalty: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<StakeConfig> for UiStakeConfig {
|
|
|
|
fn from(config: StakeConfig) -> Self {
|
|
|
|
Self {
|
|
|
|
warmup_cooldown_rate: config.warmup_cooldown_rate,
|
|
|
|
slash_penalty: config.slash_penalty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct UiConfig<T> {
|
|
|
|
pub keys: Vec<UiConfigKey>,
|
|
|
|
pub config_data: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*, crate::validator_info::ValidatorInfo, serde_json::json,
|
|
|
|
solana_config_program::create_config_account, solana_sdk::account::ReadableAccount,
|
|
|
|
};
|
2020-08-09 00:50:45 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_config() {
|
|
|
|
let stake_config = StakeConfig {
|
|
|
|
warmup_cooldown_rate: 0.25,
|
|
|
|
slash_penalty: 50,
|
|
|
|
};
|
|
|
|
let stake_config_account = create_config_account(vec![], &stake_config, 10);
|
|
|
|
assert_eq!(
|
2021-06-18 06:34:46 -07:00
|
|
|
parse_config(stake_config_account.data(), &stake_config::id()).unwrap(),
|
2020-08-09 00:50:45 -07:00
|
|
|
ConfigAccountType::StakeConfig(UiStakeConfig {
|
|
|
|
warmup_cooldown_rate: 0.25,
|
|
|
|
slash_penalty: 50,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
let validator_info = ValidatorInfo {
|
|
|
|
info: serde_json::to_string(&json!({
|
|
|
|
"name": "Solana",
|
|
|
|
}))
|
|
|
|
.unwrap(),
|
|
|
|
};
|
2020-10-19 12:12:08 -07:00
|
|
|
let info_pubkey = solana_sdk::pubkey::new_rand();
|
2020-08-09 00:50:45 -07:00
|
|
|
let validator_info_config_account = create_config_account(
|
|
|
|
vec![(validator_info::id(), false), (info_pubkey, true)],
|
|
|
|
&validator_info,
|
|
|
|
10,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2021-06-18 06:34:46 -07:00
|
|
|
parse_config(validator_info_config_account.data(), &info_pubkey).unwrap(),
|
2020-08-09 00:50:45 -07:00
|
|
|
ConfigAccountType::ValidatorInfo(UiConfig {
|
|
|
|
keys: vec![
|
|
|
|
UiConfigKey {
|
|
|
|
pubkey: validator_info::id().to_string(),
|
|
|
|
signer: false,
|
|
|
|
},
|
|
|
|
UiConfigKey {
|
|
|
|
pubkey: info_pubkey.to_string(),
|
|
|
|
signer: true,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
config_data: serde_json::from_str(r#"{"name":"Solana"}"#).unwrap(),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
let bad_data = vec![0; 4];
|
|
|
|
assert!(parse_config(&bad_data, &info_pubkey).is_err());
|
|
|
|
}
|
|
|
|
}
|