1use {
2 agave_feature_set::{FeatureSet, FEATURE_NAMES},
3 log::*,
4 solana_account::{Account, AccountSharedData},
5 solana_cluster_type::ClusterType,
6 solana_feature_gate_interface::{self as feature, Feature},
7 solana_fee_calculator::FeeRateGovernor,
8 solana_genesis_config::GenesisConfig,
9 solana_keypair::Keypair,
10 solana_native_token::LAMPORTS_PER_SOL,
11 solana_pubkey::Pubkey,
12 solana_rent::Rent,
13 solana_seed_derivable::SeedDerivable,
14 solana_signer::Signer,
15 solana_stake_interface::state::StakeStateV2,
16 solana_stake_program::stake_state,
17 solana_system_interface::program as system_program,
18 solana_vote_program::vote_state,
19 std::borrow::Borrow,
20};
21
22const VALIDATOR_LAMPORTS: u64 = 42;
24
25pub fn bootstrap_validator_stake_lamports() -> u64 {
27 Rent::default().minimum_balance(StakeStateV2::size_of())
28}
29
30pub const fn genesis_sysvar_and_builtin_program_lamports() -> u64 {
32 const NUM_BUILTIN_PROGRAMS: u64 = 7;
33 const NUM_PRECOMPILES: u64 = 2;
34 const STAKE_HISTORY_MIN_BALANCE: u64 = 114_979_200;
35 const CLOCK_SYSVAR_MIN_BALANCE: u64 = 1_169_280;
36 const RENT_SYSVAR_MIN_BALANCE: u64 = 1_009_200;
37 const EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE: u64 = 1_120_560;
38 const RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE: u64 = 42_706_560;
39
40 STAKE_HISTORY_MIN_BALANCE
41 + CLOCK_SYSVAR_MIN_BALANCE
42 + RENT_SYSVAR_MIN_BALANCE
43 + EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE
44 + RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE
45 + NUM_BUILTIN_PROGRAMS
46 + NUM_PRECOMPILES
47}
48
49pub struct ValidatorVoteKeypairs {
50 pub node_keypair: Keypair,
51 pub vote_keypair: Keypair,
52 pub stake_keypair: Keypair,
53}
54
55impl ValidatorVoteKeypairs {
56 pub fn new(node_keypair: Keypair, vote_keypair: Keypair, stake_keypair: Keypair) -> Self {
57 Self {
58 node_keypair,
59 vote_keypair,
60 stake_keypair,
61 }
62 }
63
64 pub fn new_rand() -> Self {
65 Self {
66 node_keypair: Keypair::new(),
67 vote_keypair: Keypair::new(),
68 stake_keypair: Keypair::new(),
69 }
70 }
71}
72
73pub struct GenesisConfigInfo {
74 pub genesis_config: GenesisConfig,
75 pub mint_keypair: Keypair,
76 pub voting_keypair: Keypair,
77 pub validator_pubkey: Pubkey,
78}
79
80pub fn create_genesis_config(mint_lamports: u64) -> GenesisConfigInfo {
81 create_genesis_config_with_leader(
86 mint_lamports,
87 &solana_pubkey::new_rand(), 0, )
90}
91
92pub fn create_genesis_config_with_vote_accounts(
93 mint_lamports: u64,
94 voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
95 stakes: Vec<u64>,
96) -> GenesisConfigInfo {
97 create_genesis_config_with_vote_accounts_and_cluster_type(
98 mint_lamports,
99 voting_keypairs,
100 stakes,
101 ClusterType::Development,
102 )
103}
104
105pub fn create_genesis_config_with_vote_accounts_and_cluster_type(
106 mint_lamports: u64,
107 voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
108 stakes: Vec<u64>,
109 cluster_type: ClusterType,
110) -> GenesisConfigInfo {
111 assert!(!voting_keypairs.is_empty());
112 assert_eq!(voting_keypairs.len(), stakes.len());
113
114 let mint_keypair = Keypair::new();
115 let voting_keypair = voting_keypairs[0].borrow().vote_keypair.insecure_clone();
116
117 let validator_pubkey = voting_keypairs[0].borrow().node_keypair.pubkey();
118 let genesis_config = create_genesis_config_with_leader_ex(
119 mint_lamports,
120 &mint_keypair.pubkey(),
121 &validator_pubkey,
122 &voting_keypairs[0].borrow().vote_keypair.pubkey(),
123 &voting_keypairs[0].borrow().stake_keypair.pubkey(),
124 stakes[0],
125 VALIDATOR_LAMPORTS,
126 FeeRateGovernor::new(0, 0), Rent::free(), cluster_type,
129 vec![],
130 );
131
132 let mut genesis_config_info = GenesisConfigInfo {
133 genesis_config,
134 mint_keypair,
135 voting_keypair,
136 validator_pubkey,
137 };
138
139 for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) {
140 let node_pubkey = validator_voting_keypairs.borrow().node_keypair.pubkey();
141 let vote_pubkey = validator_voting_keypairs.borrow().vote_keypair.pubkey();
142 let stake_pubkey = validator_voting_keypairs.borrow().stake_keypair.pubkey();
143
144 let node_account = Account::new(VALIDATOR_LAMPORTS, 0, &system_program::id());
146 let vote_account = vote_state::create_account(&vote_pubkey, &node_pubkey, 0, *stake);
147 let stake_account = Account::from(stake_state::create_account(
148 &stake_pubkey,
149 &vote_pubkey,
150 &vote_account,
151 &genesis_config_info.genesis_config.rent,
152 *stake,
153 ));
154
155 let vote_account = Account::from(vote_account);
156
157 genesis_config_info.genesis_config.accounts.extend(vec![
159 (node_pubkey, node_account),
160 (vote_pubkey, vote_account),
161 (stake_pubkey, stake_account),
162 ]);
163 }
164
165 genesis_config_info
166}
167
168pub fn create_genesis_config_with_leader(
169 mint_lamports: u64,
170 validator_pubkey: &Pubkey,
171 validator_stake_lamports: u64,
172) -> GenesisConfigInfo {
173 let mint_keypair = Keypair::from_seed(&[
175 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
176 25, 26, 27, 28, 29, 30, 31,
177 ])
178 .unwrap();
179
180 create_genesis_config_with_leader_with_mint_keypair(
181 mint_keypair,
182 mint_lamports,
183 validator_pubkey,
184 validator_stake_lamports,
185 )
186}
187
188pub fn create_genesis_config_with_leader_with_mint_keypair(
189 mint_keypair: Keypair,
190 mint_lamports: u64,
191 validator_pubkey: &Pubkey,
192 validator_stake_lamports: u64,
193) -> GenesisConfigInfo {
194 let voting_keypair = Keypair::from_seed(&[
196 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
197 55, 56, 57, 58, 59, 60, 61, 62, 63,
198 ])
199 .unwrap();
200
201 let genesis_config = create_genesis_config_with_leader_ex(
202 mint_lamports,
203 &mint_keypair.pubkey(),
204 validator_pubkey,
205 &voting_keypair.pubkey(),
206 &Pubkey::new_unique(),
207 validator_stake_lamports,
208 VALIDATOR_LAMPORTS,
209 FeeRateGovernor::new(0, 0), Rent::free(), ClusterType::Development,
212 vec![],
213 );
214
215 GenesisConfigInfo {
216 genesis_config,
217 mint_keypair,
218 voting_keypair,
219 validator_pubkey: *validator_pubkey,
220 }
221}
222
223pub fn activate_all_features_alpenglow(genesis_config: &mut GenesisConfig) {
224 do_activate_all_features::<true>(genesis_config);
225}
226
227pub fn activate_all_features(genesis_config: &mut GenesisConfig) {
228 do_activate_all_features::<false>(genesis_config);
229}
230
231fn do_activate_all_features<const IS_ALPENGLOW: bool>(genesis_config: &mut GenesisConfig) {
232 for feature_id in FeatureSet::default().inactive() {
234 if IS_ALPENGLOW || *feature_id != agave_feature_set::alpenglow::id() {
235 activate_feature(genesis_config, *feature_id);
236 }
237 }
238}
239
240pub fn deactivate_features(
241 genesis_config: &mut GenesisConfig,
242 features_to_deactivate: &Vec<Pubkey>,
243) {
244 for deactivate_feature_pk in features_to_deactivate {
246 if FEATURE_NAMES.contains_key(deactivate_feature_pk) {
247 genesis_config.accounts.remove(deactivate_feature_pk);
248 } else {
249 warn!(
250 "Feature {deactivate_feature_pk:?} set for deactivation is not a known Feature \
251 public key"
252 );
253 }
254 }
255}
256
257pub fn activate_feature(genesis_config: &mut GenesisConfig, feature_id: Pubkey) {
258 genesis_config.accounts.insert(
259 feature_id,
260 Account::from(feature::create_account(
261 &Feature {
262 activated_at: Some(0),
263 },
264 std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1),
265 )),
266 );
267}
268
269#[allow(clippy::too_many_arguments)]
270pub fn create_genesis_config_with_leader_ex_no_features(
271 mint_lamports: u64,
272 mint_pubkey: &Pubkey,
273 validator_pubkey: &Pubkey,
274 validator_vote_account_pubkey: &Pubkey,
275 validator_stake_account_pubkey: &Pubkey,
276 validator_stake_lamports: u64,
277 validator_lamports: u64,
278 fee_rate_governor: FeeRateGovernor,
279 rent: Rent,
280 cluster_type: ClusterType,
281 mut initial_accounts: Vec<(Pubkey, AccountSharedData)>,
282) -> GenesisConfig {
283 let validator_vote_account = vote_state::create_account(
284 validator_vote_account_pubkey,
285 validator_pubkey,
286 0,
287 validator_stake_lamports,
288 );
289
290 let validator_stake_account = stake_state::create_account(
291 validator_stake_account_pubkey,
292 validator_vote_account_pubkey,
293 &validator_vote_account,
294 &rent,
295 validator_stake_lamports,
296 );
297
298 initial_accounts.push((
299 *mint_pubkey,
300 AccountSharedData::new(mint_lamports, 0, &system_program::id()),
301 ));
302 initial_accounts.push((
303 *validator_pubkey,
304 AccountSharedData::new(validator_lamports, 0, &system_program::id()),
305 ));
306 initial_accounts.push((*validator_vote_account_pubkey, validator_vote_account));
307 initial_accounts.push((*validator_stake_account_pubkey, validator_stake_account));
308
309 let native_mint_account = solana_account::AccountSharedData::from(Account {
310 owner: spl_generic_token::token::id(),
311 data: spl_generic_token::token::native_mint::ACCOUNT_DATA.to_vec(),
312 lamports: LAMPORTS_PER_SOL,
313 executable: false,
314 rent_epoch: 1,
315 });
316 initial_accounts.push((
317 spl_generic_token::token::native_mint::id(),
318 native_mint_account,
319 ));
320
321 let mut genesis_config = GenesisConfig {
322 accounts: initial_accounts
323 .iter()
324 .cloned()
325 .map(|(key, account)| (key, Account::from(account)))
326 .collect(),
327 fee_rate_governor,
328 rent,
329 cluster_type,
330 ..GenesisConfig::default()
331 };
332
333 solana_stake_program::add_genesis_accounts(&mut genesis_config);
334
335 genesis_config
336}
337
338#[allow(clippy::too_many_arguments)]
339pub fn create_genesis_config_with_leader_ex(
340 mint_lamports: u64,
341 mint_pubkey: &Pubkey,
342 validator_pubkey: &Pubkey,
343 validator_vote_account_pubkey: &Pubkey,
344 validator_stake_account_pubkey: &Pubkey,
345 validator_stake_lamports: u64,
346 validator_lamports: u64,
347 fee_rate_governor: FeeRateGovernor,
348 rent: Rent,
349 cluster_type: ClusterType,
350 initial_accounts: Vec<(Pubkey, AccountSharedData)>,
351) -> GenesisConfig {
352 let mut genesis_config = create_genesis_config_with_leader_ex_no_features(
353 mint_lamports,
354 mint_pubkey,
355 validator_pubkey,
356 validator_vote_account_pubkey,
357 validator_stake_account_pubkey,
358 validator_stake_lamports,
359 validator_lamports,
360 fee_rate_governor,
361 rent,
362 cluster_type,
363 initial_accounts,
364 );
365
366 if genesis_config.cluster_type == ClusterType::Development {
367 activate_all_features(&mut genesis_config);
368 }
369
370 genesis_config
371}