1use {
2 solana_sdk::{
3 account::{Account, AccountSharedData},
4 feature::{self, Feature},
5 feature_set::FeatureSet,
6 fee_calculator::FeeRateGovernor,
7 genesis_config::{ClusterType, GenesisConfig},
8 pubkey::Pubkey,
9 rent::Rent,
10 signature::{Keypair, Signer},
11 stake::state::StakeState,
12 system_program,
13 },
14 solana_stake_program::stake_state,
15 solana_vote_program::vote_state,
16 std::borrow::Borrow,
17};
18
19const VALIDATOR_LAMPORTS: u64 = 42;
21
22pub fn bootstrap_validator_stake_lamports() -> u64 {
24 Rent::default().minimum_balance(StakeState::size_of())
25}
26
27pub const fn genesis_sysvar_and_builtin_program_lamports() -> u64 {
29 const NUM_BUILTIN_PROGRAMS: u64 = 4;
30 const FEES_SYSVAR_MIN_BALANCE: u64 = 946_560;
31 const STAKE_HISTORY_MIN_BALANCE: u64 = 114_979_200;
32 const CLOCK_SYSVAR_MIN_BALANCE: u64 = 1_169_280;
33 const RENT_SYSVAR_MIN_BALANCE: u64 = 1_009_200;
34 const EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE: u64 = 1_120_560;
35 const RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE: u64 = 42_706_560;
36
37 FEES_SYSVAR_MIN_BALANCE
38 + STAKE_HISTORY_MIN_BALANCE
39 + CLOCK_SYSVAR_MIN_BALANCE
40 + RENT_SYSVAR_MIN_BALANCE
41 + EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE
42 + RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE
43 + NUM_BUILTIN_PROGRAMS
44}
45
46pub struct ValidatorVoteKeypairs {
47 pub node_keypair: Keypair,
48 pub vote_keypair: Keypair,
49 pub stake_keypair: Keypair,
50}
51
52impl ValidatorVoteKeypairs {
53 pub fn new(node_keypair: Keypair, vote_keypair: Keypair, stake_keypair: Keypair) -> Self {
54 Self {
55 node_keypair,
56 vote_keypair,
57 stake_keypair,
58 }
59 }
60
61 pub fn new_rand() -> Self {
62 Self {
63 node_keypair: Keypair::new(),
64 vote_keypair: Keypair::new(),
65 stake_keypair: Keypair::new(),
66 }
67 }
68}
69
70pub struct GenesisConfigInfo {
71 pub genesis_config: GenesisConfig,
72 pub mint_keypair: Keypair,
73 pub voting_keypair: Keypair,
74 pub validator_pubkey: Pubkey,
75}
76
77pub fn create_genesis_config(mint_lamports: u64) -> GenesisConfigInfo {
78 create_genesis_config_with_leader(
83 mint_lamports,
84 &solana_sdk::pubkey::new_rand(), 0, )
87}
88
89pub fn create_genesis_config_with_vote_accounts(
90 mint_lamports: u64,
91 voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
92 stakes: Vec<u64>,
93) -> GenesisConfigInfo {
94 create_genesis_config_with_vote_accounts_and_cluster_type(
95 mint_lamports,
96 voting_keypairs,
97 stakes,
98 ClusterType::Development,
99 )
100}
101
102pub fn create_genesis_config_with_vote_accounts_and_cluster_type(
103 mint_lamports: u64,
104 voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
105 stakes: Vec<u64>,
106 cluster_type: ClusterType,
107) -> GenesisConfigInfo {
108 assert!(!voting_keypairs.is_empty());
109 assert_eq!(voting_keypairs.len(), stakes.len());
110
111 let mint_keypair = Keypair::new();
112 let voting_keypair =
113 Keypair::from_bytes(&voting_keypairs[0].borrow().vote_keypair.to_bytes()).unwrap();
114
115 let validator_pubkey = voting_keypairs[0].borrow().node_keypair.pubkey();
116 let genesis_config = create_genesis_config_with_leader_ex(
117 mint_lamports,
118 &mint_keypair.pubkey(),
119 &validator_pubkey,
120 &voting_keypairs[0].borrow().vote_keypair.pubkey(),
121 &voting_keypairs[0].borrow().stake_keypair.pubkey(),
122 stakes[0],
123 VALIDATOR_LAMPORTS,
124 FeeRateGovernor::new(0, 0), Rent::free(), cluster_type,
127 vec![],
128 );
129
130 let mut genesis_config_info = GenesisConfigInfo {
131 genesis_config,
132 mint_keypair,
133 voting_keypair,
134 validator_pubkey,
135 };
136
137 for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) {
138 let node_pubkey = validator_voting_keypairs.borrow().node_keypair.pubkey();
139 let vote_pubkey = validator_voting_keypairs.borrow().vote_keypair.pubkey();
140 let stake_pubkey = validator_voting_keypairs.borrow().stake_keypair.pubkey();
141
142 let node_account = Account::new(VALIDATOR_LAMPORTS, 0, &system_program::id());
144 let vote_account = vote_state::create_account(&vote_pubkey, &node_pubkey, 0, *stake);
145 let stake_account = Account::from(stake_state::create_account(
146 &stake_pubkey,
147 &vote_pubkey,
148 &vote_account,
149 &genesis_config_info.genesis_config.rent,
150 *stake,
151 ));
152
153 let vote_account = Account::from(vote_account);
154
155 genesis_config_info.genesis_config.accounts.extend(vec![
157 (node_pubkey, node_account),
158 (vote_pubkey, vote_account),
159 (stake_pubkey, stake_account),
160 ]);
161 }
162
163 genesis_config_info
164}
165
166pub fn create_genesis_config_with_leader(
167 mint_lamports: u64,
168 validator_pubkey: &Pubkey,
169 validator_stake_lamports: u64,
170) -> GenesisConfigInfo {
171 let mint_keypair = Keypair::new();
172 let voting_keypair = Keypair::new();
173
174 let genesis_config = create_genesis_config_with_leader_ex(
175 mint_lamports,
176 &mint_keypair.pubkey(),
177 validator_pubkey,
178 &voting_keypair.pubkey(),
179 &solana_sdk::pubkey::new_rand(),
180 validator_stake_lamports,
181 VALIDATOR_LAMPORTS,
182 FeeRateGovernor::new(0, 0), Rent::free(), ClusterType::Development,
185 vec![],
186 );
187
188 GenesisConfigInfo {
189 genesis_config,
190 mint_keypair,
191 voting_keypair,
192 validator_pubkey: *validator_pubkey,
193 }
194}
195
196pub fn activate_all_features(genesis_config: &mut GenesisConfig) {
197 for feature_id in FeatureSet::default().inactive {
199 activate_feature(genesis_config, feature_id);
200 }
201}
202
203pub fn activate_feature(genesis_config: &mut GenesisConfig, feature_id: Pubkey) {
204 genesis_config.accounts.insert(
205 feature_id,
206 Account::from(feature::create_account(
207 &Feature {
208 activated_at: Some(0),
209 },
210 std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1),
211 )),
212 );
213}
214
215#[allow(clippy::too_many_arguments)]
216pub fn create_genesis_config_with_leader_ex(
217 mint_lamports: u64,
218 mint_pubkey: &Pubkey,
219 validator_pubkey: &Pubkey,
220 validator_vote_account_pubkey: &Pubkey,
221 validator_stake_account_pubkey: &Pubkey,
222 validator_stake_lamports: u64,
223 validator_lamports: u64,
224 fee_rate_governor: FeeRateGovernor,
225 rent: Rent,
226 cluster_type: ClusterType,
227 mut initial_accounts: Vec<(Pubkey, AccountSharedData)>,
228) -> GenesisConfig {
229 let validator_vote_account = vote_state::create_account(
230 validator_vote_account_pubkey,
231 validator_pubkey,
232 0,
233 validator_stake_lamports,
234 );
235
236 let validator_stake_account = stake_state::create_account(
237 validator_stake_account_pubkey,
238 validator_vote_account_pubkey,
239 &validator_vote_account,
240 &rent,
241 validator_stake_lamports,
242 );
243
244 initial_accounts.push((
245 *mint_pubkey,
246 AccountSharedData::new(mint_lamports, 0, &system_program::id()),
247 ));
248 initial_accounts.push((
249 *validator_pubkey,
250 AccountSharedData::new(validator_lamports, 0, &system_program::id()),
251 ));
252 initial_accounts.push((*validator_vote_account_pubkey, validator_vote_account));
253 initial_accounts.push((*validator_stake_account_pubkey, validator_stake_account));
254
255 let mut genesis_config = GenesisConfig {
256 accounts: initial_accounts
257 .iter()
258 .cloned()
259 .map(|(key, account)| (key, Account::from(account)))
260 .collect(),
261 fee_rate_governor,
262 rent,
263 cluster_type,
264 ..GenesisConfig::default()
265 };
266
267 solana_stake_program::add_genesis_accounts(&mut genesis_config);
268 if genesis_config.cluster_type == ClusterType::Development {
269 activate_all_features(&mut genesis_config);
270 }
271
272 genesis_config
273}