diem_types/on_chain_config/
mod.rsuse crate::{
    access_path::AccessPath,
    account_address::AccountAddress,
    account_config::CORE_CODE_ADDRESS,
    event::{EventHandle, EventKey},
};
use anyhow::{format_err, Result};
use move_core_types::{
    identifier::Identifier,
    language_storage::{StructTag, TypeTag},
    move_resource::MoveResource,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{collections::HashMap, fmt, sync::Arc};
mod diem_version;
mod registered_currencies;
mod validator_set;
mod vm_config;
mod vm_publishing_option;
pub use self::{
    diem_version::{DiemVersion, DIEM_MAX_KNOWN_VERSION, DIEM_VERSION_2},
    registered_currencies::RegisteredCurrencies,
    validator_set::{NextValidatorSetProposal, ValidatorSet},
    vm_config::VMConfig,
    vm_publishing_option::VMPublishingOption,
};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct ConfigID(&'static str, &'static str);
const CONFIG_ADDRESS_STR: &str = "0xA550C18";
pub fn config_address() -> AccountAddress {
    AccountAddress::from_hex_literal(CONFIG_ADDRESS_STR)
        .expect("failed to get address")
}
impl ConfigID {
    pub fn access_path(self) -> AccessPath {
        access_path_for_config(
            AccountAddress::from_hex_literal(self.0)
                .expect("failed to get address"),
            Identifier::new(self.1).expect("failed to get Identifier"),
        )
    }
}
impl fmt::Display for ConfigID {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "OnChain config ID [address: {}, identifier: {}]",
            self.0, self.1
        )
    }
}
pub const ON_CHAIN_CONFIG_REGISTRY: &[ConfigID] = &[
    ValidatorSet::CONFIG_ID,
    ];
#[derive(Clone, Debug, PartialEq)]
pub struct OnChainConfigPayload {
    epoch: u64,
    configs: Arc<HashMap<ConfigID, Vec<u8>>>,
}
impl OnChainConfigPayload {
    pub fn new(epoch: u64, configs: Arc<HashMap<ConfigID, Vec<u8>>>) -> Self {
        Self { epoch, configs }
    }
    pub fn epoch(&self) -> u64 { self.epoch }
    pub fn get<T: OnChainConfig>(&self) -> Result<T> {
        let bytes = self.configs.get(&T::CONFIG_ID).ok_or_else(|| {
            format_err!("[on-chain cfg] config not in payload")
        })?;
        T::deserialize_into_config(bytes)
    }
    pub fn configs(&self) -> &HashMap<ConfigID, Vec<u8>> { &self.configs }
}
impl fmt::Display for OnChainConfigPayload {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut config_ids = "".to_string();
        for id in self.configs.keys() {
            config_ids += &id.to_string();
        }
        write!(
            f,
            "OnChainConfigPayload [epoch: {}, configs: {}]",
            self.epoch, config_ids
        )
    }
}
pub trait ConfigStorage {
    fn fetch_config(&self, access_path: AccessPath) -> Option<Vec<u8>>;
}
pub trait OnChainConfig: Send + Sync + DeserializeOwned {
    const ADDRESS: &'static str = CONFIG_ADDRESS_STR;
    const IDENTIFIER: &'static str;
    const CONFIG_ID: ConfigID = ConfigID(Self::ADDRESS, Self::IDENTIFIER);
    fn deserialize_default_impl(bytes: &[u8]) -> Result<Self> {
        bcs::from_bytes::<Self>(&bytes).map_err(|e| {
            format_err!(
                "[on-chain config] Failed to deserialize into config: {}",
                e
            )
        })
    }
    fn deserialize_into_config(bytes: &[u8]) -> Result<Self> {
        Self::deserialize_default_impl(bytes)
    }
    fn fetch_config<T>(storage: &T) -> Option<Self>
    where T: ConfigStorage {
        storage
            .fetch_config(Self::CONFIG_ID.access_path())
            .and_then(|bytes| Self::deserialize_into_config(&bytes).ok())
    }
}
pub fn new_epoch_event_key() -> EventKey {
    EventKey::new_from_address(&config_address(), 4)
}
pub fn access_path_for_config(
    address: AccountAddress, config_name: Identifier,
) -> AccessPath {
    AccessPath::new(
        address,
        AccessPath::resource_access_vec(StructTag {
            address: CORE_CODE_ADDRESS,
            module: Identifier::new("DiemConfig").unwrap(),
            name: Identifier::new("DiemConfig").unwrap(),
            type_params: vec![TypeTag::Struct(StructTag {
                address: CORE_CODE_ADDRESS,
                module: config_name.clone(),
                name: config_name,
                type_params: vec![],
            })],
        }),
    )
}
#[derive(Debug, Deserialize, Serialize)]
pub struct ConfigurationResource {
    epoch: u64,
    last_reconfiguration_time: u64,
    events: EventHandle,
}
impl ConfigurationResource {
    pub fn epoch(&self) -> u64 { self.epoch }
    pub fn last_reconfiguration_time(&self) -> u64 {
        self.last_reconfiguration_time
    }
    pub fn events(&self) -> &EventHandle { &self.events }
    #[cfg(feature = "fuzzing")]
    pub fn bump_epoch_for_test(&self) -> Self {
        let epoch = self.epoch + 1;
        let last_reconfiguration_time = self.last_reconfiguration_time + 1;
        let mut events = self.events.clone();
        *events.count_mut() += 1;
        Self {
            epoch,
            last_reconfiguration_time,
            events,
        }
    }
}
#[cfg(feature = "fuzzing")]
impl Default for ConfigurationResource {
    fn default() -> Self {
        Self {
            epoch: 0,
            last_reconfiguration_time: 0,
            events: EventHandle::new_from_address(
                &crate::account_config::diem_root_address(),
                16,
            ),
        }
    }
}
impl MoveResource for ConfigurationResource {
    const MODULE_NAME: &'static str = "DiemConfig";
    const STRUCT_NAME: &'static str = "Configuration";
}