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