use std::path::Path;
use num_rational::Ratio;
use semver::Version;
use serde::{Deserialize, Serialize};
use casper_execution_engine::{
core::engine_state::genesis::GenesisAccount, shared::wasm_config::WasmConfig,
};
use casper_types::auction::EraId;
use super::{chainspec, DeployConfig, Error, HighwayConfig};
use crate::{
types::Timestamp,
utils::{read_file, External},
};
const DEFAULT_CHAIN_NAME: &str = "casper-devnet";
const DEFAULT_MINT_INSTALLER_PATH: &str = "mint_install.wasm";
const DEFAULT_POS_INSTALLER_PATH: &str = "pos_install.wasm";
const DEFAULT_STANDARD_PAYMENT_INSTALLER_PATH: &str = "standard_payment_install.wasm";
const DEFAULT_AUCTION_INSTALLER_PATH: &str = "auction_install.wasm";
const DEFAULT_ACCOUNTS_CSV_PATH: &str = "accounts.csv";
const DEFAULT_UPGRADE_INSTALLER_PATH: &str = "upgrade_install.wasm";
const DEFAULT_VALIDATOR_SLOTS: u32 = 5;
const DEFAULT_AUCTION_DELAY: u64 = 3;
const DEFAULT_LOCKED_FUNDS_PERIOD: EraId = 15;
const DEFAULT_ROUND_SEIGNIORAGE_RATE: Ratio<u64> = Ratio::new_raw(6414, 623437335209);
const DEFAULT_UNBONDING_DELAY: EraId = 14;
const DEFAULT_WASMLESS_TRANSFER_COST: u64 = 10_000;
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug)]
struct Genesis {
name: String,
timestamp: Timestamp,
validator_slots: u32,
auction_delay: u64,
locked_funds_period: EraId,
protocol_version: Version,
round_seigniorage_rate: Ratio<u64>,
unbonding_delay: EraId,
wasmless_transfer_cost: u64,
mint_installer_path: External<Vec<u8>>,
pos_installer_path: External<Vec<u8>>,
standard_payment_installer_path: External<Vec<u8>>,
auction_installer_path: External<Vec<u8>>,
accounts_path: External<Vec<GenesisAccount>>,
}
impl Default for Genesis {
fn default() -> Self {
Genesis {
name: String::from(DEFAULT_CHAIN_NAME),
timestamp: Timestamp::zero(),
validator_slots: DEFAULT_VALIDATOR_SLOTS,
auction_delay: DEFAULT_AUCTION_DELAY,
locked_funds_period: DEFAULT_LOCKED_FUNDS_PERIOD,
protocol_version: Version::from((1, 0, 0)),
round_seigniorage_rate: DEFAULT_ROUND_SEIGNIORAGE_RATE,
unbonding_delay: DEFAULT_UNBONDING_DELAY,
wasmless_transfer_cost: DEFAULT_WASMLESS_TRANSFER_COST,
mint_installer_path: External::path(DEFAULT_MINT_INSTALLER_PATH),
pos_installer_path: External::path(DEFAULT_POS_INSTALLER_PATH),
standard_payment_installer_path: External::path(
DEFAULT_STANDARD_PAYMENT_INSTALLER_PATH,
),
auction_installer_path: External::path(DEFAULT_AUCTION_INSTALLER_PATH),
accounts_path: External::path(DEFAULT_ACCOUNTS_CSV_PATH),
}
}
}
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct UpgradePoint {
protocol_version: Version,
upgrade_installer_path: Option<External<Vec<u8>>>,
activation_point: chainspec::ActivationPoint,
new_wasm_config: Option<WasmConfig>,
new_deploy_config: Option<DeployConfig>,
new_validator_slots: Option<u32>,
new_wasmless_transfer_cost: Option<u64>,
}
impl From<&chainspec::UpgradePoint> for UpgradePoint {
fn from(upgrade_point: &chainspec::UpgradePoint) -> Self {
UpgradePoint {
protocol_version: upgrade_point.protocol_version.clone(),
upgrade_installer_path: Some(External::path(DEFAULT_UPGRADE_INSTALLER_PATH)),
activation_point: upgrade_point.activation_point,
new_wasm_config: upgrade_point.new_wasm_config,
new_deploy_config: upgrade_point.new_deploy_config,
new_validator_slots: upgrade_point.new_validator_slots,
new_wasmless_transfer_cost: upgrade_point.new_wasmless_transfer_cost,
}
}
}
impl UpgradePoint {
fn try_into_chainspec_upgrade_point<P: AsRef<Path>>(
self,
root: P,
) -> Result<chainspec::UpgradePoint, Error> {
let upgrade_installer_bytes = self
.upgrade_installer_path
.map(|ext_vec| ext_vec.load(root.as_ref()))
.transpose()
.map_err(Error::LoadUpgradeInstaller)?;
let upgrade_installer_args = None;
Ok(chainspec::UpgradePoint {
activation_point: self.activation_point,
protocol_version: self.protocol_version,
upgrade_installer_bytes,
upgrade_installer_args,
new_wasm_config: self.new_wasm_config,
new_deploy_config: self.new_deploy_config,
new_validator_slots: self.new_validator_slots,
new_wasmless_transfer_cost: self.new_wasmless_transfer_cost,
})
}
}
#[derive(Default, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub(super) struct ChainspecConfig {
genesis: Genesis,
highway: HighwayConfig,
deploys: DeployConfig,
upgrade: Option<Vec<UpgradePoint>>,
wasm_config: WasmConfig,
}
impl From<&chainspec::Chainspec> for ChainspecConfig {
fn from(chainspec: &chainspec::Chainspec) -> Self {
let genesis = Genesis {
name: chainspec.genesis.name.clone(),
timestamp: chainspec.genesis.timestamp,
validator_slots: chainspec.genesis.validator_slots,
auction_delay: chainspec.genesis.auction_delay,
locked_funds_period: chainspec.genesis.locked_funds_period,
protocol_version: chainspec.genesis.protocol_version.clone(),
round_seigniorage_rate: chainspec.genesis.round_seigniorage_rate,
unbonding_delay: chainspec.genesis.unbonding_delay,
wasmless_transfer_cost: chainspec.genesis.wasmless_transfer_cost,
mint_installer_path: External::path(DEFAULT_MINT_INSTALLER_PATH),
pos_installer_path: External::path(DEFAULT_POS_INSTALLER_PATH),
standard_payment_installer_path: External::path(
DEFAULT_STANDARD_PAYMENT_INSTALLER_PATH,
),
auction_installer_path: External::path(DEFAULT_AUCTION_INSTALLER_PATH),
accounts_path: External::path(DEFAULT_ACCOUNTS_CSV_PATH),
};
let highway = chainspec.genesis.highway_config.clone();
let deploys = chainspec.genesis.deploy_config;
let wasm_config = chainspec.genesis.wasm_config;
let upgrades = chainspec
.upgrades
.iter()
.map(UpgradePoint::from)
.collect::<Vec<_>>();
let upgrade = if upgrades.is_empty() {
None
} else {
Some(upgrades)
};
ChainspecConfig {
genesis,
highway,
deploys,
upgrade,
wasm_config,
}
}
}
pub(super) fn parse_toml<P: AsRef<Path>>(chainspec_path: P) -> Result<chainspec::Chainspec, Error> {
let chainspec: ChainspecConfig =
toml::from_slice(&read_file(chainspec_path.as_ref()).map_err(Error::LoadChainspec)?)?;
let root = chainspec_path
.as_ref()
.parent()
.unwrap_or_else(|| Path::new(""));
let mint_installer_bytes = chainspec
.genesis
.mint_installer_path
.load(root)
.map_err(Error::LoadMintInstaller)?;
let pos_installer_bytes = chainspec
.genesis
.pos_installer_path
.load(root)
.map_err(Error::LoadPosInstaller)?;
let standard_payment_installer_bytes = chainspec
.genesis
.standard_payment_installer_path
.load(root)
.map_err(Error::LoadStandardPaymentInstaller)?;
let auction_installer_bytes = chainspec
.genesis
.auction_installer_path
.load(root)
.map_err(Error::LoadAuctionInstaller)?;
let accounts: Vec<GenesisAccount> = chainspec
.genesis
.accounts_path
.load(root)
.map_err(Error::LoadGenesisAccounts)?;
let genesis = chainspec::GenesisConfig {
name: chainspec.genesis.name,
timestamp: chainspec.genesis.timestamp,
validator_slots: chainspec.genesis.validator_slots,
auction_delay: chainspec.genesis.auction_delay,
locked_funds_period: chainspec.genesis.locked_funds_period,
round_seigniorage_rate: chainspec.genesis.round_seigniorage_rate,
unbonding_delay: chainspec.genesis.unbonding_delay,
wasmless_transfer_cost: chainspec.genesis.wasmless_transfer_cost,
protocol_version: chainspec.genesis.protocol_version,
mint_installer_bytes,
pos_installer_bytes,
standard_payment_installer_bytes,
auction_installer_bytes,
accounts,
wasm_config: chainspec.wasm_config,
deploy_config: chainspec.deploys,
highway_config: chainspec.highway,
};
let mut upgrades = vec![];
for upgrade_point in chainspec.upgrade.unwrap_or_default().into_iter() {
upgrades.push(upgrade_point.try_into_chainspec_upgrade_point(root)?);
}
Ok(chainspec::Chainspec { genesis, upgrades })
}