From eb73002299d79ef82e7f8171e48bc233ed719513 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 2 Dec 2024 15:20:50 +0400 Subject: [PATCH 1/3] extract genesis-config crate --- Cargo.lock | 33 ++ Cargo.toml | 1 + programs/sbf/Cargo.lock | 29 ++ sdk/Cargo.toml | 3 + sdk/genesis-config/Cargo.toml | 88 +++++ sdk/{ => genesis-config}/src/hard_forks.rs | 12 +- sdk/genesis-config/src/lib.rs | 339 ++++++++++++++++++ sdk/{ => genesis-config}/src/shred_version.rs | 7 +- sdk/src/genesis_config.rs | 328 +---------------- sdk/src/lib.rs | 5 +- svm/examples/Cargo.lock | 29 ++ 11 files changed, 537 insertions(+), 337 deletions(-) create mode 100644 sdk/genesis-config/Cargo.toml rename sdk/{ => genesis-config}/src/hard_forks.rs (92%) create mode 100644 sdk/genesis-config/src/lib.rs rename sdk/{ => genesis-config}/src/shred_version.rs (94%) diff --git a/Cargo.lock b/Cargo.lock index fa207f9103fc37..f75daf84549ee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7124,6 +7124,38 @@ dependencies = [ "tempfile", ] +[[package]] +name = "solana-genesis-config" +version = "2.2.0" +dependencies = [ + "bincode", + "byteorder", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-genesis-config", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-logger", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-signer", + "solana-time-utils", +] + [[package]] name = "solana-genesis-utils" version = "2.2.0" @@ -8563,6 +8595,7 @@ dependencies = [ "solana-fee-structure", "solana-frozen-abi", "solana-frozen-abi-macro", + "solana-genesis-config", "solana-inflation", "solana-instruction", "solana-keypair", diff --git a/Cargo.toml b/Cargo.toml index 4eb6e6bbe29e92..04a0bdcb1a582c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -480,6 +480,7 @@ solana-frozen-abi-macro = { path = "sdk/frozen-abi/macro", version = "=2.2.0" } solana-tps-client = { path = "tps-client", version = "=2.2.0" } solana-file-download = { path = "sdk/file-download", version = "=2.2.0" } solana-genesis = { path = "genesis", version = "=2.2.0" } +solana-genesis-config = { path = "sdk/genesis-config", version = "=2.2.0" } solana-genesis-utils = { path = "genesis-utils", version = "=2.2.0" } agave-geyser-plugin-interface = { path = "geyser-plugin-interface", version = "=2.2.0" } solana-geyser-plugin-manager = { path = "geyser-plugin-manager", version = "=2.2.0" } diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 655ab1471f4066..35de51df742914 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5672,6 +5672,34 @@ dependencies = [ "reqwest", ] +[[package]] +name = "solana-genesis-config" +version = "2.2.0" +dependencies = [ + "bincode", + "byteorder 1.5.0", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-signer", + "solana-time-utils", +] + [[package]] name = "solana-genesis-utils" version = "2.2.0" @@ -7256,6 +7284,7 @@ dependencies = [ "solana-epoch-info", "solana-feature-set", "solana-fee-structure", + "solana-genesis-config", "solana-inflation", "solana-instruction", "solana-keypair", diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 4dabd2cb4d83eb..4865e235b133b4 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -40,6 +40,7 @@ full = [ "dep:solana-ed25519-program", "dep:solana-compute-budget-interface", "dep:solana-keypair", + "dep:solana-genesis-config", "dep:solana-precompile-error", "dep:solana-precompiles", "dep:solana-presigner", @@ -73,6 +74,7 @@ frozen-abi = [ "solana-fee-structure/frozen-abi", "solana-account/frozen-abi", "solana-cluster-type/frozen-abi", + "solana-genesis-config/frozen-abi", "solana-inflation/frozen-abi", "solana-poh-config/frozen-abi", "solana-program/frozen-abi", @@ -140,6 +142,7 @@ solana-frozen-abi = { workspace = true, optional = true, features = [ solana-frozen-abi-macro = { workspace = true, optional = true, features = [ "frozen-abi", ] } +solana-genesis-config = { workspace = true, optional = true, features = ["bincode"] } solana-inflation = { workspace = true, features = ["serde"] } solana-instruction = { workspace = true } solana-keypair = { workspace = true, optional = true, features = [ diff --git a/sdk/genesis-config/Cargo.toml b/sdk/genesis-config/Cargo.toml new file mode 100644 index 00000000000000..d48c04e741dcc6 --- /dev/null +++ b/sdk/genesis-config/Cargo.toml @@ -0,0 +1,88 @@ +[package] +name = "solana-genesis-config" +description = "Solana genesis config." +documentation = "https://docs.rs/solana-genesis-config" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[dependencies] +bincode = { workspace = true, optional = true } +byteorder = { workspace = true } +chrono = { workspace = true, features = ["alloc"], optional = true } +memmap2 = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-account = { workspace = true } +solana-clock = { workspace = true } +solana-cluster-type = { workspace = true } +solana-epoch-schedule = { workspace = true } +solana-fee-calculator = { workspace = true } +solana-frozen-abi = { workspace = true, optional = true, features = [ + "frozen-abi", +] } +solana-frozen-abi-macro = { workspace = true, optional = true, features = [ + "frozen-abi", +] } +solana-hash = { workspace = true } +solana-inflation = { workspace = true } +solana-keypair = { workspace = true } +solana-logger = { workspace = true, optional = true } +solana-native-token = { workspace = true, optional = true } +solana-poh-config = { workspace = true } +solana-pubkey = { workspace = true } +solana-rent = { workspace = true } +solana-sdk-ids = { workspace = true } +solana-sha256-hasher = { workspace = true } +solana-signer = { workspace = true } +solana-time-utils = { workspace = true } + +[dev-dependencies] +solana-genesis-config = { path = ".", features = ["dev-context-only-utils"] } +solana-pubkey = { workspace = true, features = ["rand"] } + +[features] +bincode = [ + "dep:bincode", + "dep:chrono", + "dep:memmap2", + "dep:solana-native-token", + "serde", +] +dev-context-only-utils = ["bincode"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-logger", + "solana-account/frozen-abi", + "solana-cluster-type/frozen-abi", + "solana-epoch-schedule/frozen-abi", + "solana-fee-calculator/frozen-abi", + "solana-inflation/frozen-abi", + "solana-poh-config/frozen-abi", + "solana-pubkey/frozen-abi", + "solana-rent/frozen-abi", +] +serde = [ + "dep:serde", + "dep:serde_derive", + "solana-account/serde", + "solana-cluster-type/serde", + "solana-epoch-schedule/serde", + "solana-fee-calculator/serde", + "solana-inflation/serde", + "solana-poh-config/serde", + "solana-pubkey/serde", + "solana-rent/serde", +] + +[lints] +workspace = true diff --git a/sdk/src/hard_forks.rs b/sdk/genesis-config/src/hard_forks.rs similarity index 92% rename from sdk/src/hard_forks.rs rename to sdk/genesis-config/src/hard_forks.rs index dda66a2949138d..f02fc2c85fa66d 100644 --- a/sdk/src/hard_forks.rs +++ b/sdk/genesis-config/src/hard_forks.rs @@ -1,15 +1,17 @@ //! The list of slot boundaries at which a hard fork should //! occur. -#![cfg(feature = "full")] - use { byteorder::{ByteOrder, LittleEndian}, - solana_sdk::clock::Slot, + solana_clock::Slot, }; -#[cfg_attr(feature = "frozen-abi", derive(AbiExample))] -#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct HardForks { hard_forks: Vec<(Slot, usize)>, } diff --git a/sdk/genesis-config/src/lib.rs b/sdk/genesis-config/src/lib.rs new file mode 100644 index 00000000000000..a02514f558e22b --- /dev/null +++ b/sdk/genesis-config/src/lib.rs @@ -0,0 +1,339 @@ +//! The chain's genesis config. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] + +#[cfg(feature = "bincode")] +use { + crate::shred_version::compute_shred_version, + bincode::{deserialize, serialize}, + chrono::{TimeZone, Utc}, + memmap2::Mmap, + solana_hash::Hash, + solana_native_token::lamports_to_sol, + solana_sha256_hasher::hash, + std::{ + fmt, + fs::{File, OpenOptions}, + io::Write, + path::{Path, PathBuf}, + }, +}; +use { + solana_account::{Account, AccountSharedData}, + solana_clock::{UnixTimestamp, DEFAULT_TICKS_PER_SLOT}, + solana_cluster_type::ClusterType, + solana_epoch_schedule::EpochSchedule, + solana_fee_calculator::FeeRateGovernor, + solana_inflation::Inflation, + solana_keypair::Keypair, + solana_poh_config::PohConfig, + solana_pubkey::Pubkey, + solana_rent::Rent, + solana_sdk_ids::system_program, + solana_signer::Signer, + solana_time_utils::years_as_slots, + std::{ + collections::BTreeMap, + time::{SystemTime, UNIX_EPOCH}, + }, +}; + +pub mod hard_forks; +pub mod shred_version; + +pub const DEFAULT_GENESIS_FILE: &str = "genesis.bin"; +pub const DEFAULT_GENESIS_ARCHIVE: &str = "genesis.tar.bz2"; +pub const DEFAULT_GENESIS_DOWNLOAD_PATH: &str = "/genesis.tar.bz2"; +// deprecated default that is no longer used +pub const UNUSED_DEFAULT: u64 = 1024; + +#[cfg_attr( + feature = "frozen-abi", + derive(solana_frozen_abi_macro::AbiExample), + solana_frozen_abi_macro::frozen_abi(digest = "D9VFRSj4fodCuKFC9omQY2zY2Uw8wo6SzJFLeMJaVigm") +)] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] +#[derive(Debug, Clone, PartialEq)] +pub struct GenesisConfig { + /// when the network (bootstrap validator) was started relative to the UNIX Epoch + pub creation_time: UnixTimestamp, + /// initial accounts + pub accounts: BTreeMap, + /// built-in programs + pub native_instruction_processors: Vec<(String, Pubkey)>, + /// accounts for network rewards, these do not count towards capitalization + pub rewards_pools: BTreeMap, + pub ticks_per_slot: u64, + pub unused: u64, + /// network speed configuration + pub poh_config: PohConfig, + /// this field exists only to ensure that the binary layout of GenesisConfig remains compatible + /// with the Solana v0.23 release line + pub __backwards_compat_with_v0_23: u64, + /// transaction fee config + pub fee_rate_governor: FeeRateGovernor, + /// rent config + pub rent: Rent, + /// inflation config + pub inflation: Inflation, + /// how slots map to epochs + pub epoch_schedule: EpochSchedule, + /// network runlevel + pub cluster_type: ClusterType, +} + +// useful for basic tests +pub fn create_genesis_config(lamports: u64) -> (GenesisConfig, Keypair) { + let faucet_keypair = Keypair::new(); + ( + GenesisConfig::new( + &[( + faucet_keypair.pubkey(), + AccountSharedData::new(lamports, 0, &system_program::id()), + )], + &[], + ), + faucet_keypair, + ) +} + +impl Default for GenesisConfig { + fn default() -> Self { + Self { + creation_time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as UnixTimestamp, + accounts: BTreeMap::default(), + native_instruction_processors: Vec::default(), + rewards_pools: BTreeMap::default(), + ticks_per_slot: DEFAULT_TICKS_PER_SLOT, + unused: UNUSED_DEFAULT, + poh_config: PohConfig::default(), + inflation: Inflation::default(), + __backwards_compat_with_v0_23: 0, + fee_rate_governor: FeeRateGovernor::default(), + rent: Rent::default(), + epoch_schedule: EpochSchedule::default(), + cluster_type: ClusterType::Development, + } + } +} + +impl GenesisConfig { + pub fn new( + accounts: &[(Pubkey, AccountSharedData)], + native_instruction_processors: &[(String, Pubkey)], + ) -> Self { + Self { + accounts: accounts + .iter() + .cloned() + .map(|(key, account)| (key, Account::from(account))) + .collect::>(), + native_instruction_processors: native_instruction_processors.to_vec(), + ..GenesisConfig::default() + } + } + + #[cfg(feature = "bincode")] + pub fn hash(&self) -> Hash { + let serialized = serialize(&self).unwrap(); + hash(&serialized) + } + + #[cfg(feature = "bincode")] + fn genesis_filename(ledger_path: &Path) -> PathBuf { + Path::new(ledger_path).join(DEFAULT_GENESIS_FILE) + } + + #[cfg(feature = "bincode")] + pub fn load(ledger_path: &Path) -> Result { + let filename = Self::genesis_filename(ledger_path); + let file = OpenOptions::new() + .read(true) + .open(&filename) + .map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Unable to open {filename:?}: {err:?}"), + ) + })?; + + //UNSAFE: Required to create a Mmap + let mem = unsafe { Mmap::map(&file) }.map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Unable to map {filename:?}: {err:?}"), + ) + })?; + + let genesis_config = deserialize(&mem).map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Unable to deserialize {filename:?}: {err:?}"), + ) + })?; + Ok(genesis_config) + } + + #[cfg(feature = "bincode")] + pub fn write(&self, ledger_path: &Path) -> Result<(), std::io::Error> { + let serialized = serialize(&self).map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Unable to serialize: {err:?}"), + ) + })?; + + std::fs::create_dir_all(ledger_path)?; + + let mut file = File::create(Self::genesis_filename(ledger_path))?; + file.write_all(&serialized) + } + + pub fn add_account(&mut self, pubkey: Pubkey, account: AccountSharedData) { + self.accounts.insert(pubkey, Account::from(account)); + } + + pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) { + self.native_instruction_processors.push((name, program_id)); + } + + pub fn hashes_per_tick(&self) -> Option { + self.poh_config.hashes_per_tick + } + + pub fn ticks_per_slot(&self) -> u64 { + self.ticks_per_slot + } + + pub fn ns_per_slot(&self) -> u128 { + self.poh_config + .target_tick_duration + .as_nanos() + .saturating_mul(self.ticks_per_slot() as u128) + } + + pub fn slots_per_year(&self) -> f64 { + years_as_slots( + 1.0, + &self.poh_config.target_tick_duration, + self.ticks_per_slot(), + ) + } +} + +#[cfg(feature = "bincode")] +impl fmt::Display for GenesisConfig { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "\ + Creation time: {}\n\ + Cluster type: {:?}\n\ + Genesis hash: {}\n\ + Shred version: {}\n\ + Ticks per slot: {:?}\n\ + Hashes per tick: {:?}\n\ + Target tick duration: {:?}\n\ + Slots per epoch: {}\n\ + Warmup epochs: {}abled\n\ + Slots per year: {}\n\ + {:?}\n\ + {:?}\n\ + {:?}\n\ + Capitalization: {} SOL in {} accounts\n\ + Native instruction processors: {:#?}\n\ + Rewards pool: {:#?}\n\ + ", + Utc.timestamp_opt(self.creation_time, 0) + .unwrap() + .to_rfc3339(), + self.cluster_type, + self.hash(), + compute_shred_version(&self.hash(), None), + self.ticks_per_slot, + self.poh_config.hashes_per_tick, + self.poh_config.target_tick_duration, + self.epoch_schedule.slots_per_epoch, + if self.epoch_schedule.warmup { + "en" + } else { + "dis" + }, + self.slots_per_year(), + self.inflation, + self.rent, + self.fee_rate_governor, + lamports_to_sol( + self.accounts + .iter() + .map(|(pubkey, account)| { + assert!(account.lamports > 0, "{:?}", (pubkey, account)); + account.lamports + }) + .sum::() + ), + self.accounts.len(), + self.native_instruction_processors, + self.rewards_pools, + ) + } +} + +#[cfg(test)] +mod tests { + use {super::*, solana_keypair::Keypair, solana_signer::Signer, std::path::PathBuf}; + + fn make_tmp_path(name: &str) -> PathBuf { + let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()); + let keypair = Keypair::new(); + + let path = [ + out_dir, + "tmp".to_string(), + format!("{}-{}", name, keypair.pubkey()), + ] + .iter() + .collect(); + + // whack any possible collision + let _ignored = std::fs::remove_dir_all(&path); + // whack any possible collision + let _ignored = std::fs::remove_file(&path); + + path + } + + #[test] + fn test_genesis_config() { + let faucet_keypair = Keypair::new(); + let mut config = GenesisConfig::default(); + config.add_account( + faucet_keypair.pubkey(), + AccountSharedData::new(10_000, 0, &Pubkey::default()), + ); + config.add_account( + solana_pubkey::new_rand(), + AccountSharedData::new(1, 0, &Pubkey::default()), + ); + config.add_native_instruction_processor("hi".to_string(), solana_pubkey::new_rand()); + + assert_eq!(config.accounts.len(), 2); + assert!(config + .accounts + .iter() + .any(|(pubkey, account)| *pubkey == faucet_keypair.pubkey() + && account.lamports == 10_000)); + + let path = &make_tmp_path("genesis_config"); + config.write(path).expect("write"); + let loaded_config = GenesisConfig::load(path).expect("load"); + assert_eq!(config.hash(), loaded_config.hash()); + let _ignored = std::fs::remove_file(path); + } +} diff --git a/sdk/src/shred_version.rs b/sdk/genesis-config/src/shred_version.rs similarity index 94% rename from sdk/src/shred_version.rs rename to sdk/genesis-config/src/shred_version.rs index 52560a1709c102..a7442ca92cfabd 100644 --- a/sdk/src/shred_version.rs +++ b/sdk/genesis-config/src/shred_version.rs @@ -2,12 +2,7 @@ //! //! [shred]: https://solana.com/docs/terminology#shred -#![cfg(feature = "full")] - -use solana_sdk::{ - hard_forks::HardForks, - hash::{extend_and_hash, Hash}, -}; +use {crate::hard_forks::HardForks, solana_hash::Hash, solana_sha256_hasher::extend_and_hash}; pub fn version_from_hash(hash: &Hash) -> u16 { let hash = hash.as_ref(); diff --git a/sdk/src/genesis_config.rs b/sdk/src/genesis_config.rs index af86e8e3005659..a1794f19882592 100644 --- a/sdk/src/genesis_config.rs +++ b/sdk/src/genesis_config.rs @@ -1,331 +1,11 @@ -//! The chain's genesis config. - #![cfg(feature = "full")] - #[deprecated( since = "2.2.0", note = "Use `solana_cluster_type::ClusterType` instead." )] pub use solana_cluster_type::ClusterType; -use { - crate::{ - clock::{UnixTimestamp, DEFAULT_TICKS_PER_SLOT}, - epoch_schedule::EpochSchedule, - fee_calculator::FeeRateGovernor, - hash::{hash, Hash}, - inflation::Inflation, - poh_config::PohConfig, - pubkey::Pubkey, - rent::Rent, - shred_version::compute_shred_version, - signature::{Keypair, Signer}, - system_program, - timing::years_as_slots, - }, - bincode::{deserialize, serialize}, - chrono::{TimeZone, Utc}, - memmap2::Mmap, - solana_account::{Account, AccountSharedData}, - solana_native_token::lamports_to_sol, - std::{ - collections::BTreeMap, - fmt, - fs::{File, OpenOptions}, - io::Write, - path::{Path, PathBuf}, - time::{SystemTime, UNIX_EPOCH}, - }, +#[deprecated(since = "2.2.0", note = "Use `solana-genesis-config` crate instead.")] +pub use solana_genesis_config::{ + create_genesis_config, GenesisConfig, DEFAULT_GENESIS_ARCHIVE, DEFAULT_GENESIS_DOWNLOAD_PATH, + DEFAULT_GENESIS_FILE, UNUSED_DEFAULT, }; - -pub const DEFAULT_GENESIS_FILE: &str = "genesis.bin"; -pub const DEFAULT_GENESIS_ARCHIVE: &str = "genesis.tar.bz2"; -pub const DEFAULT_GENESIS_DOWNLOAD_PATH: &str = "/genesis.tar.bz2"; - -// deprecated default that is no longer used -pub const UNUSED_DEFAULT: u64 = 1024; - -#[cfg_attr( - feature = "frozen-abi", - derive(AbiExample), - frozen_abi(digest = "D9VFRSj4fodCuKFC9omQY2zY2Uw8wo6SzJFLeMJaVigm") -)] -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct GenesisConfig { - /// when the network (bootstrap validator) was started relative to the UNIX Epoch - pub creation_time: UnixTimestamp, - /// initial accounts - pub accounts: BTreeMap, - /// built-in programs - pub native_instruction_processors: Vec<(String, Pubkey)>, - /// accounts for network rewards, these do not count towards capitalization - pub rewards_pools: BTreeMap, - pub ticks_per_slot: u64, - pub unused: u64, - /// network speed configuration - pub poh_config: PohConfig, - /// this field exists only to ensure that the binary layout of GenesisConfig remains compatible - /// with the Solana v0.23 release line - pub __backwards_compat_with_v0_23: u64, - /// transaction fee config - pub fee_rate_governor: FeeRateGovernor, - /// rent config - pub rent: Rent, - /// inflation config - pub inflation: Inflation, - /// how slots map to epochs - pub epoch_schedule: EpochSchedule, - /// network runlevel - pub cluster_type: ClusterType, -} - -// useful for basic tests -pub fn create_genesis_config(lamports: u64) -> (GenesisConfig, Keypair) { - let faucet_keypair = Keypair::new(); - ( - GenesisConfig::new( - &[( - faucet_keypair.pubkey(), - AccountSharedData::new(lamports, 0, &system_program::id()), - )], - &[], - ), - faucet_keypair, - ) -} - -impl Default for GenesisConfig { - fn default() -> Self { - Self { - creation_time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() as UnixTimestamp, - accounts: BTreeMap::default(), - native_instruction_processors: Vec::default(), - rewards_pools: BTreeMap::default(), - ticks_per_slot: DEFAULT_TICKS_PER_SLOT, - unused: UNUSED_DEFAULT, - poh_config: PohConfig::default(), - inflation: Inflation::default(), - __backwards_compat_with_v0_23: 0, - fee_rate_governor: FeeRateGovernor::default(), - rent: Rent::default(), - epoch_schedule: EpochSchedule::default(), - cluster_type: ClusterType::Development, - } - } -} - -impl GenesisConfig { - pub fn new( - accounts: &[(Pubkey, AccountSharedData)], - native_instruction_processors: &[(String, Pubkey)], - ) -> Self { - Self { - accounts: accounts - .iter() - .cloned() - .map(|(key, account)| (key, Account::from(account))) - .collect::>(), - native_instruction_processors: native_instruction_processors.to_vec(), - ..GenesisConfig::default() - } - } - - pub fn hash(&self) -> Hash { - let serialized = serialize(&self).unwrap(); - hash(&serialized) - } - - fn genesis_filename(ledger_path: &Path) -> PathBuf { - Path::new(ledger_path).join(DEFAULT_GENESIS_FILE) - } - - pub fn load(ledger_path: &Path) -> Result { - let filename = Self::genesis_filename(ledger_path); - let file = OpenOptions::new() - .read(true) - .open(&filename) - .map_err(|err| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("Unable to open {filename:?}: {err:?}"), - ) - })?; - - //UNSAFE: Required to create a Mmap - let mem = unsafe { Mmap::map(&file) }.map_err(|err| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("Unable to map {filename:?}: {err:?}"), - ) - })?; - - let genesis_config = deserialize(&mem).map_err(|err| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("Unable to deserialize {filename:?}: {err:?}"), - ) - })?; - Ok(genesis_config) - } - - pub fn write(&self, ledger_path: &Path) -> Result<(), std::io::Error> { - let serialized = serialize(&self).map_err(|err| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("Unable to serialize: {err:?}"), - ) - })?; - - std::fs::create_dir_all(ledger_path)?; - - let mut file = File::create(Self::genesis_filename(ledger_path))?; - file.write_all(&serialized) - } - - pub fn add_account(&mut self, pubkey: Pubkey, account: AccountSharedData) { - self.accounts.insert(pubkey, Account::from(account)); - } - - pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) { - self.native_instruction_processors.push((name, program_id)); - } - - pub fn hashes_per_tick(&self) -> Option { - self.poh_config.hashes_per_tick - } - - pub fn ticks_per_slot(&self) -> u64 { - self.ticks_per_slot - } - - pub fn ns_per_slot(&self) -> u128 { - self.poh_config - .target_tick_duration - .as_nanos() - .saturating_mul(self.ticks_per_slot() as u128) - } - - pub fn slots_per_year(&self) -> f64 { - years_as_slots( - 1.0, - &self.poh_config.target_tick_duration, - self.ticks_per_slot(), - ) - } -} - -impl fmt::Display for GenesisConfig { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "\ - Creation time: {}\n\ - Cluster type: {:?}\n\ - Genesis hash: {}\n\ - Shred version: {}\n\ - Ticks per slot: {:?}\n\ - Hashes per tick: {:?}\n\ - Target tick duration: {:?}\n\ - Slots per epoch: {}\n\ - Warmup epochs: {}abled\n\ - Slots per year: {}\n\ - {:?}\n\ - {:?}\n\ - {:?}\n\ - Capitalization: {} SOL in {} accounts\n\ - Native instruction processors: {:#?}\n\ - Rewards pool: {:#?}\n\ - ", - Utc.timestamp_opt(self.creation_time, 0) - .unwrap() - .to_rfc3339(), - self.cluster_type, - self.hash(), - compute_shred_version(&self.hash(), None), - self.ticks_per_slot, - self.poh_config.hashes_per_tick, - self.poh_config.target_tick_duration, - self.epoch_schedule.slots_per_epoch, - if self.epoch_schedule.warmup { - "en" - } else { - "dis" - }, - self.slots_per_year(), - self.inflation, - self.rent, - self.fee_rate_governor, - lamports_to_sol( - self.accounts - .iter() - .map(|(pubkey, account)| { - assert!(account.lamports > 0, "{:?}", (pubkey, account)); - account.lamports - }) - .sum::() - ), - self.accounts.len(), - self.native_instruction_processors, - self.rewards_pools, - ) - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::signature::{Keypair, Signer}, - std::path::PathBuf, - }; - - fn make_tmp_path(name: &str) -> PathBuf { - let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()); - let keypair = Keypair::new(); - - let path = [ - out_dir, - "tmp".to_string(), - format!("{}-{}", name, keypair.pubkey()), - ] - .iter() - .collect(); - - // whack any possible collision - let _ignored = std::fs::remove_dir_all(&path); - // whack any possible collision - let _ignored = std::fs::remove_file(&path); - - path - } - - #[test] - fn test_genesis_config() { - let faucet_keypair = Keypair::new(); - let mut config = GenesisConfig::default(); - config.add_account( - faucet_keypair.pubkey(), - AccountSharedData::new(10_000, 0, &Pubkey::default()), - ); - config.add_account( - solana_sdk::pubkey::new_rand(), - AccountSharedData::new(1, 0, &Pubkey::default()), - ); - config.add_native_instruction_processor("hi".to_string(), solana_sdk::pubkey::new_rand()); - - assert_eq!(config.accounts.len(), 2); - assert!(config - .accounts - .iter() - .any(|(pubkey, account)| *pubkey == faucet_keypair.pubkey() - && account.lamports == 10_000)); - - let path = &make_tmp_path("genesis_config"); - config.write(path).expect("write"); - let loaded_config = GenesisConfig::load(path).expect("load"); - assert_eq!(config.hash(), loaded_config.hash()); - let _ignored = std::fs::remove_file(path); - } -} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 9b81f1ca316b8c..7f85986bc0cfca 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -69,7 +69,6 @@ pub mod example_mocks; pub mod exit; pub mod feature; pub mod genesis_config; -pub mod hard_forks; pub mod hash; pub mod inner_instruction; pub mod log; @@ -90,7 +89,6 @@ pub mod reward_type { pub use solana_reward_info::RewardType; } pub mod rpc_port; -pub mod shred_version; pub mod signature; pub mod signer; pub mod transaction; @@ -128,6 +126,9 @@ pub use solana_epoch_info as epoch_info; pub use solana_feature_set as feature_set; #[deprecated(since = "2.2.0", note = "Use `solana-fee-structure` crate instead")] pub use solana_fee_structure as fee; +#[cfg(feature = "full")] +#[deprecated(since = "2.2.0", note = "Use `solana-genesis-config` crate instead")] +pub use solana_genesis_config::{hard_forks, shred_version}; #[deprecated(since = "2.1.0", note = "Use `solana-inflation` crate instead")] pub use solana_inflation as inflation; #[deprecated(since = "2.1.0", note = "Use `solana-packet` crate instead")] diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index c61a01f945fe01..a4635c813a1616 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5503,6 +5503,34 @@ dependencies = [ "solana-native-token", ] +[[package]] +name = "solana-genesis-config" +version = "2.2.0" +dependencies = [ + "bincode", + "byteorder", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-signer", + "solana-time-utils", +] + [[package]] name = "solana-geyser-plugin-manager" version = "2.2.0" @@ -6584,6 +6612,7 @@ dependencies = [ "solana-epoch-info", "solana-feature-set", "solana-fee-structure", + "solana-genesis-config", "solana-inflation", "solana-instruction", "solana-keypair", From 07fe169352ddcf23bdbc67b1c9b96a9c89a02cbc Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 2 Dec 2024 19:15:15 +0400 Subject: [PATCH 2/3] missing cfg_attr --- sdk/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 7f85986bc0cfca..bb54881d2001d2 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -235,7 +235,7 @@ macro_rules! saturating_add_assign { pub extern crate bs58; extern crate log as logger; -#[cfg_attr(not(target_os = "solana"), macro_use)] +#[cfg_attr(feature = "full", macro_use)] extern crate serde_derive; #[cfg_attr(feature = "frozen-abi", macro_use)] From 4e495da3c79622700164fb264f31ce143f94d366 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 5 Dec 2024 18:06:16 +0400 Subject: [PATCH 3/3] update digest --- runtime/src/bank/serde_snapshot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/bank/serde_snapshot.rs b/runtime/src/bank/serde_snapshot.rs index 9078ef9edbbe19..40ae913736019b 100644 --- a/runtime/src/bank/serde_snapshot.rs +++ b/runtime/src/bank/serde_snapshot.rs @@ -570,7 +570,7 @@ mod tests { #[cfg_attr( feature = "frozen-abi", derive(AbiExample), - frozen_abi(digest = "2bWtYJSWVVvCEnBw6W2PsYZaR7RVs2V7CthFcHArdbUR") + frozen_abi(digest = "5DZE4EAVGiJqQi3xsv7qj4xr22Tgx8vX6D3hS5vGh55E") )] #[derive(Serialize)] pub struct BankAbiTestWrapper {