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