1use {
2 log::*,
3 solana_feature_set::{FeatureSet, FEATURE_NAMES},
4 solana_sdk::{
5 account::{Account, AccountSharedData},
6 feature::{self, Feature},
7 fee_calculator::FeeRateGovernor,
8 genesis_config::{ClusterType, GenesisConfig},
9 native_token::sol_to_lamports,
10 pubkey::Pubkey,
11 rent::Rent,
12 signature::{Keypair, Signer},
13 signer::SeedDerivable,
14 stake::state::StakeStateV2,
15 system_program,
16 },
17 solana_stake_program::stake_state,
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 = 9;
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(genesis_config: &mut GenesisConfig) {
224 for feature_id in FeatureSet::default().inactive {
226 activate_feature(genesis_config, feature_id);
227 }
228}
229
230pub fn deactivate_features(
231 genesis_config: &mut GenesisConfig,
232 features_to_deactivate: &Vec<Pubkey>,
233) {
234 for deactivate_feature_pk in features_to_deactivate {
236 if FEATURE_NAMES.contains_key(deactivate_feature_pk) {
237 genesis_config.accounts.remove(deactivate_feature_pk);
238 } else {
239 warn!(
240 "Feature {:?} set for deactivation is not a known Feature public key",
241 deactivate_feature_pk
242 );
243 }
244 }
245}
246
247pub fn activate_feature(genesis_config: &mut GenesisConfig, feature_id: Pubkey) {
248 genesis_config.accounts.insert(
249 feature_id,
250 Account::from(feature::create_account(
251 &Feature {
252 activated_at: Some(0),
253 },
254 std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1),
255 )),
256 );
257}
258
259#[allow(clippy::too_many_arguments)]
260pub fn create_genesis_config_with_leader_ex_no_features(
261 mint_lamports: u64,
262 mint_pubkey: &Pubkey,
263 validator_pubkey: &Pubkey,
264 validator_vote_account_pubkey: &Pubkey,
265 validator_stake_account_pubkey: &Pubkey,
266 validator_stake_lamports: u64,
267 validator_lamports: u64,
268 fee_rate_governor: FeeRateGovernor,
269 rent: Rent,
270 cluster_type: ClusterType,
271 mut initial_accounts: Vec<(Pubkey, AccountSharedData)>,
272) -> GenesisConfig {
273 let validator_vote_account = vote_state::create_account(
274 validator_vote_account_pubkey,
275 validator_pubkey,
276 0,
277 validator_stake_lamports,
278 );
279
280 let validator_stake_account = stake_state::create_account(
281 validator_stake_account_pubkey,
282 validator_vote_account_pubkey,
283 &validator_vote_account,
284 &rent,
285 validator_stake_lamports,
286 );
287
288 initial_accounts.push((
289 *mint_pubkey,
290 AccountSharedData::new(mint_lamports, 0, &system_program::id()),
291 ));
292 initial_accounts.push((
293 *validator_pubkey,
294 AccountSharedData::new(validator_lamports, 0, &system_program::id()),
295 ));
296 initial_accounts.push((*validator_vote_account_pubkey, validator_vote_account));
297 initial_accounts.push((*validator_stake_account_pubkey, validator_stake_account));
298
299 let native_mint_account = solana_sdk::account::AccountSharedData::from(Account {
300 owner: solana_inline_spl::token::id(),
301 data: solana_inline_spl::token::native_mint::ACCOUNT_DATA.to_vec(),
302 lamports: sol_to_lamports(1.),
303 executable: false,
304 rent_epoch: 1,
305 });
306 initial_accounts.push((
307 solana_inline_spl::token::native_mint::id(),
308 native_mint_account,
309 ));
310
311 let mut genesis_config = GenesisConfig {
312 accounts: initial_accounts
313 .iter()
314 .cloned()
315 .map(|(key, account)| (key, Account::from(account)))
316 .collect(),
317 fee_rate_governor,
318 rent,
319 cluster_type,
320 ..GenesisConfig::default()
321 };
322
323 solana_stake_program::add_genesis_accounts(&mut genesis_config);
324
325 genesis_config
326}
327
328#[allow(clippy::too_many_arguments)]
329pub fn create_genesis_config_with_leader_ex(
330 mint_lamports: u64,
331 mint_pubkey: &Pubkey,
332 validator_pubkey: &Pubkey,
333 validator_vote_account_pubkey: &Pubkey,
334 validator_stake_account_pubkey: &Pubkey,
335 validator_stake_lamports: u64,
336 validator_lamports: u64,
337 fee_rate_governor: FeeRateGovernor,
338 rent: Rent,
339 cluster_type: ClusterType,
340 initial_accounts: Vec<(Pubkey, AccountSharedData)>,
341) -> GenesisConfig {
342 let mut genesis_config = create_genesis_config_with_leader_ex_no_features(
343 mint_lamports,
344 mint_pubkey,
345 validator_pubkey,
346 validator_vote_account_pubkey,
347 validator_stake_account_pubkey,
348 validator_stake_lamports,
349 validator_lamports,
350 fee_rate_governor,
351 rent,
352 cluster_type,
353 initial_accounts,
354 );
355
356 if genesis_config.cluster_type == ClusterType::Development {
357 activate_all_features(&mut genesis_config);
358 }
359
360 genesis_config
361}