mod account_config;
mod delegator_config;
mod validator_config;
use std::path::Path;
use datasize::DataSize;
use serde::{Deserialize, Deserializer, Serialize};
use casper_execution_engine::core::engine_state::GenesisAccount;
use casper_types::bytesrepr::{self, FromBytes, ToBytes};
#[cfg(test)]
use crate::testing::TestRng;
use crate::utils::{self, Loadable};
use super::error::ChainspecAccountsLoadError;
pub use account_config::AccountConfig;
pub use delegator_config::DelegatorConfig;
pub use validator_config::ValidatorConfig;
const CHAINSPEC_ACCOUNTS_FILENAME: &str = "accounts.toml";
fn sorted_vec_deserializer<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
T: Deserialize<'de> + Ord,
D: Deserializer<'de>,
{
let mut vec = Vec::<T>::deserialize(deserializer)?;
vec.sort_unstable();
Ok(vec)
}
#[derive(PartialEq, Eq, Serialize, Deserialize, DataSize, Debug, Clone)]
pub struct AccountsConfig {
#[serde(deserialize_with = "sorted_vec_deserializer")]
accounts: Vec<AccountConfig>,
#[serde(default, deserialize_with = "sorted_vec_deserializer")]
delegators: Vec<DelegatorConfig>,
}
impl AccountsConfig {
pub fn new(accounts: Vec<AccountConfig>, delegators: Vec<DelegatorConfig>) -> Self {
Self {
accounts,
delegators,
}
}
pub fn accounts(&self) -> &[AccountConfig] {
&self.accounts
}
pub fn delegators(&self) -> &[DelegatorConfig] {
&self.delegators
}
#[cfg(test)]
pub fn random(rng: &mut TestRng) -> Self {
let alpha = AccountConfig::random(rng);
let accounts = vec![
alpha.clone(),
AccountConfig::random(rng),
AccountConfig::random(rng),
AccountConfig::random(rng),
];
let mut delegator = DelegatorConfig::random(rng);
delegator.validator_public_key = alpha.public_key;
let delegators = vec![delegator];
AccountsConfig {
accounts,
delegators,
}
}
}
impl ToBytes for AccountsConfig {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut buffer = bytesrepr::allocate_buffer(self)?;
buffer.extend(self.accounts.to_bytes()?);
buffer.extend(self.delegators.to_bytes()?);
Ok(buffer)
}
fn serialized_length(&self) -> usize {
self.accounts.serialized_length() + self.delegators.serialized_length()
}
}
impl FromBytes for AccountsConfig {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (accounts, remainder) = FromBytes::from_bytes(bytes)?;
let (delegators, remainder) = FromBytes::from_bytes(remainder)?;
let accounts_config = AccountsConfig::new(accounts, delegators);
Ok((accounts_config, remainder))
}
}
impl Loadable for AccountsConfig {
type Error = ChainspecAccountsLoadError;
fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Self::Error> {
let accounts_path = path.as_ref().join(CHAINSPEC_ACCOUNTS_FILENAME);
if !accounts_path.is_file() {
return Ok(AccountsConfig::new(vec![], vec![]));
}
let bytes = utils::read_file(accounts_path)?;
let toml_chainspec: AccountsConfig = toml::from_slice(&bytes)?;
Ok(toml_chainspec)
}
}
impl From<AccountsConfig> for Vec<GenesisAccount> {
fn from(accounts_config: AccountsConfig) -> Self {
let mut genesis_accounts = Vec::with_capacity(accounts_config.accounts.len());
for account_config in accounts_config.accounts {
let genesis_account = account_config.into();
genesis_accounts.push(genesis_account);
}
for delegator_config in accounts_config.delegators {
let genesis_account = delegator_config.into();
genesis_accounts.push(genesis_account);
}
genesis_accounts
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialization_roundtrip() {
let mut rng = TestRng::new();
let accounts_config = AccountsConfig::random(&mut rng);
bytesrepr::test_serialization_roundtrip(&accounts_config);
}
}