1use std::net::{IpAddr, SocketAddr};
6
7use anyhow::Result;
8use fastcrypto::traits::KeyPair;
9use iota_config::{
10 Config,
11 genesis::{GenesisCeremonyParameters, TokenAllocation},
12 local_ip_utils,
13 node::{DEFAULT_COMMISSION_RATE, DEFAULT_VALIDATOR_GAS_PRICE},
14};
15use iota_genesis_builder::{
16 SnapshotSource,
17 validator_info::{GenesisValidatorInfo, ValidatorInfo},
18};
19use iota_types::{
20 base_types::IotaAddress,
21 crypto::{
22 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, IotaKeyPair, NetworkKeyPair,
23 NetworkPublicKey, PublicKey, generate_proof_of_possession, get_key_pair_from_rng,
24 },
25 multiaddr::Multiaddr,
26};
27use rand::{SeedableRng, rngs::StdRng};
28use serde::{Deserialize, Serialize};
29use tracing::info;
30
31#[derive(Serialize, Deserialize, Debug)]
33pub struct SsfnGenesisConfig {
34 pub p2p_address: Multiaddr,
35 pub network_key_pair: Option<NetworkKeyPair>,
36}
37
38#[derive(Serialize, Deserialize)]
40pub struct ValidatorGenesisConfig {
41 #[serde(default = "default_bls12381_key_pair")]
42 pub authority_key_pair: AuthorityKeyPair,
43 #[serde(default = "default_ed25519_key_pair")]
44 pub protocol_key_pair: NetworkKeyPair,
45 #[serde(default = "default_iota_key_pair")]
46 pub account_key_pair: IotaKeyPair,
47 #[serde(default = "default_ed25519_key_pair")]
48 pub network_key_pair: NetworkKeyPair,
49 pub network_address: Multiaddr,
50 pub p2p_address: Multiaddr,
51 pub p2p_listen_address: Option<SocketAddr>,
52 #[serde(default = "default_socket_address")]
53 pub metrics_address: SocketAddr,
54 pub gas_price: u64,
55 pub commission_rate: u64,
56 pub primary_address: Multiaddr,
57 #[serde(default = "default_stake")]
58 pub stake: u64,
59 pub name: Option<String>,
60}
61
62impl ValidatorGenesisConfig {
63 pub fn to_validator_info(&self, name: String) -> GenesisValidatorInfo {
64 let authority_key: AuthorityPublicKeyBytes = self.authority_key_pair.public().into();
65 let account_key: PublicKey = self.account_key_pair.public();
66 let network_key: NetworkPublicKey = self.network_key_pair.public().clone();
67 let protocol_key: NetworkPublicKey = self.protocol_key_pair.public().clone();
68 let network_address = self.network_address.clone();
69
70 let info = ValidatorInfo {
71 name,
72 authority_key,
73 protocol_key,
74 network_key,
75 account_address: IotaAddress::from(&account_key),
76 gas_price: self.gas_price,
77 commission_rate: self.commission_rate,
78 network_address,
79 p2p_address: self.p2p_address.clone(),
80 primary_address: self.primary_address.clone(),
81 description: String::new(),
82 image_url: String::new(),
83 project_url: String::new(),
84 };
85 let proof_of_possession = generate_proof_of_possession(
86 &self.authority_key_pair,
87 (&self.account_key_pair.public()).into(),
88 );
89 GenesisValidatorInfo {
90 info,
91 proof_of_possession,
92 }
93 }
94
95 pub fn to_validator_info_with_random_name(&self) -> GenesisValidatorInfo {
97 self.to_validator_info(self.authority_key_pair.public().to_string())
98 }
99}
100
101#[derive(Default)]
102pub struct ValidatorGenesisConfigBuilder {
103 authority_key_pair: Option<AuthorityKeyPair>,
104 account_key_pair: Option<AccountKeyPair>,
105 ip: Option<String>,
106 gas_price: Option<u64>,
107 port_offset: Option<u16>,
110 p2p_listen_ip_address: Option<IpAddr>,
113}
114
115impl ValidatorGenesisConfigBuilder {
116 pub fn new() -> Self {
117 Self::default()
118 }
119
120 pub fn with_authority_key_pair(mut self, key_pair: AuthorityKeyPair) -> Self {
121 self.authority_key_pair = Some(key_pair);
122 self
123 }
124
125 pub fn with_account_key_pair(mut self, key_pair: AccountKeyPair) -> Self {
126 self.account_key_pair = Some(key_pair);
127 self
128 }
129
130 pub fn with_ip(mut self, ip: String) -> Self {
131 self.ip = Some(ip);
132 self
133 }
134
135 pub fn with_gas_price(mut self, gas_price: u64) -> Self {
136 self.gas_price = Some(gas_price);
137 self
138 }
139
140 pub fn with_deterministic_ports(mut self, port_offset: u16) -> Self {
141 self.port_offset = Some(port_offset);
142 self
143 }
144
145 pub fn with_p2p_listen_ip_address(mut self, p2p_listen_ip_address: IpAddr) -> Self {
146 self.p2p_listen_ip_address = Some(p2p_listen_ip_address);
147 self
148 }
149
150 pub fn build<R: rand::RngCore + rand::CryptoRng>(self, rng: &mut R) -> ValidatorGenesisConfig {
151 let ip = self.ip.unwrap_or_else(local_ip_utils::get_new_ip);
152 let localhost = local_ip_utils::localhost_for_testing();
153
154 let authority_key_pair = self
155 .authority_key_pair
156 .unwrap_or_else(|| get_key_pair_from_rng(rng).1);
157 let account_key_pair = self
158 .account_key_pair
159 .unwrap_or_else(|| get_key_pair_from_rng(rng).1);
160 let gas_price = self.gas_price.unwrap_or(DEFAULT_VALIDATOR_GAS_PRICE);
161
162 let (protocol_key_pair, network_key_pair): (NetworkKeyPair, NetworkKeyPair) =
163 (get_key_pair_from_rng(rng).1, get_key_pair_from_rng(rng).1);
164
165 let (network_address, p2p_address, metrics_address, primary_address) =
166 if let Some(offset) = self.port_offset {
167 (
168 local_ip_utils::new_deterministic_tcp_address_for_testing(&ip, offset),
169 local_ip_utils::new_deterministic_udp_address_for_testing(&ip, offset + 1),
170 local_ip_utils::new_deterministic_tcp_address_for_testing(&ip, offset + 2)
171 .with_zero_ip(),
172 local_ip_utils::new_deterministic_udp_address_for_testing(&ip, offset + 3),
173 )
174 } else {
175 (
176 local_ip_utils::new_tcp_address_for_testing(&ip),
177 local_ip_utils::new_udp_address_for_testing(&ip),
178 local_ip_utils::new_tcp_address_for_testing(&localhost),
179 local_ip_utils::new_udp_address_for_testing(&ip),
180 )
181 };
182
183 let p2p_listen_address = self
184 .p2p_listen_ip_address
185 .map(|ip| SocketAddr::new(ip, p2p_address.port().unwrap()));
186
187 ValidatorGenesisConfig {
188 authority_key_pair,
189 protocol_key_pair,
190 account_key_pair: account_key_pair.into(),
191 network_key_pair,
192 network_address,
193 p2p_address,
194 p2p_listen_address,
195 metrics_address: metrics_address.to_socket_addr().unwrap(),
196 gas_price,
197 commission_rate: DEFAULT_COMMISSION_RATE,
198 primary_address,
199 stake: iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_NANOS,
200 name: None,
201 }
202 }
203}
204
205#[derive(Serialize, Deserialize, Default)]
206pub struct GenesisConfig {
207 pub ssfn_config_info: Option<Vec<SsfnGenesisConfig>>,
208 pub validator_config_info: Option<Vec<ValidatorGenesisConfig>>,
209 pub parameters: GenesisCeremonyParameters,
210 pub accounts: Vec<AccountConfig>,
211 pub migration_sources: Vec<SnapshotSource>,
212 pub delegator: Option<IotaAddress>,
213}
214
215impl Config for GenesisConfig {}
216
217impl GenesisConfig {
218 pub fn generate_accounts<R: rand::RngCore + rand::CryptoRng>(
219 &self,
220 mut rng: R,
221 ) -> Result<(Vec<AccountKeyPair>, Vec<TokenAllocation>)> {
222 let mut addresses = Vec::new();
223 let mut allocations = Vec::new();
224
225 info!("Creating accounts and token allocations...");
226
227 let mut keys = Vec::new();
228 for account in &self.accounts {
229 let address = if let Some(address) = account.address {
230 address
231 } else {
232 let (address, keypair) = get_key_pair_from_rng(&mut rng);
233 keys.push(keypair);
234 address
235 };
236
237 addresses.push(address);
238
239 account.gas_amounts.iter().for_each(|a| {
241 allocations.push(TokenAllocation {
242 recipient_address: address,
243 amount_nanos: *a,
244 staked_with_validator: None,
245 staked_with_timelock_expiration: None,
246 });
247 });
248 }
249
250 Ok((keys, allocations))
251 }
252}
253
254fn default_socket_address() -> SocketAddr {
255 local_ip_utils::new_local_tcp_socket_for_testing()
256}
257
258fn default_stake() -> u64 {
259 iota_types::governance::VALIDATOR_LOW_STAKE_THRESHOLD_NANOS
260}
261
262fn default_bls12381_key_pair() -> AuthorityKeyPair {
263 get_key_pair_from_rng(&mut rand::rngs::OsRng).1
264}
265
266fn default_ed25519_key_pair() -> NetworkKeyPair {
267 get_key_pair_from_rng(&mut rand::rngs::OsRng).1
268}
269
270fn default_iota_key_pair() -> IotaKeyPair {
271 IotaKeyPair::Ed25519(get_key_pair_from_rng(&mut rand::rngs::OsRng).1)
272}
273
274#[derive(Serialize, Deserialize, Debug, Clone)]
275pub struct AccountConfig {
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub address: Option<IotaAddress>,
278 pub gas_amounts: Vec<u64>,
279}
280
281pub const DEFAULT_GAS_AMOUNT: u64 = 30_000_000_000_000_000;
282pub const DEFAULT_NUMBER_OF_AUTHORITIES: usize = 4;
283const DEFAULT_NUMBER_OF_ACCOUNT: usize = 5;
284pub const DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT: usize = 5;
285
286impl GenesisConfig {
287 pub const BENCHMARKS_RNG_SEED: u64 = 0;
290 pub const BENCHMARKS_PORT_OFFSET: u16 = 2000;
292 const BENCHMARK_GAS_AMOUNT: u64 = 50_000_000_000_000_000;
294 const BENCHMARK_EPOCH_DURATION_MS: u64 = 60 * 60 * 1000;
296
297 pub fn for_local_testing() -> Self {
298 Self::custom_genesis(
299 DEFAULT_NUMBER_OF_ACCOUNT,
300 DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT,
301 )
302 }
303
304 pub fn for_local_testing_with_addresses(addresses: Vec<IotaAddress>) -> Self {
305 Self::custom_genesis_with_addresses(addresses, DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT)
306 }
307
308 pub fn custom_genesis(num_accounts: usize, num_objects_per_account: usize) -> Self {
309 let mut accounts = Vec::new();
310 for _ in 0..num_accounts {
311 accounts.push(AccountConfig {
312 address: None,
313 gas_amounts: vec![DEFAULT_GAS_AMOUNT; num_objects_per_account],
314 })
315 }
316
317 Self {
318 accounts,
319 ..Default::default()
320 }
321 }
322
323 pub fn custom_genesis_with_addresses(
324 addresses: Vec<IotaAddress>,
325 num_objects_per_account: usize,
326 ) -> Self {
327 let mut accounts = Vec::new();
328 for address in addresses {
329 accounts.push(AccountConfig {
330 address: Some(address),
331 gas_amounts: vec![DEFAULT_GAS_AMOUNT; num_objects_per_account],
332 })
333 }
334
335 Self {
336 accounts,
337 ..Default::default()
338 }
339 }
340
341 pub fn new_for_benchmarks(ips: &[String]) -> Self {
348 let mut rng = StdRng::seed_from_u64(Self::BENCHMARKS_RNG_SEED);
351 let validator_config_info: Vec<_> = ips
352 .iter()
353 .enumerate()
354 .map(|(i, ip)| {
355 ValidatorGenesisConfigBuilder::new()
356 .with_ip(ip.to_string())
357 .with_deterministic_ports(Self::BENCHMARKS_PORT_OFFSET + 10 * i as u16)
358 .with_p2p_listen_ip_address("0.0.0.0".parse().unwrap())
359 .build(&mut rng)
360 })
361 .collect();
362
363 let account_configs = Self::benchmark_gas_keys(validator_config_info.len())
365 .iter()
366 .map(|gas_key| {
367 let gas_address = IotaAddress::from(&gas_key.public());
368
369 AccountConfig {
370 address: Some(gas_address),
371 gas_amounts: vec![Self::BENCHMARK_GAS_AMOUNT; 5],
375 }
376 })
377 .collect();
378
379 let parameters = GenesisCeremonyParameters {
382 chain_start_timestamp_ms: 0,
383 epoch_duration_ms: Self::BENCHMARK_EPOCH_DURATION_MS,
384 ..GenesisCeremonyParameters::new()
385 };
386
387 GenesisConfig {
389 ssfn_config_info: None,
390 validator_config_info: Some(validator_config_info),
391 parameters,
392 accounts: account_configs,
393 migration_sources: Default::default(),
394 delegator: Default::default(),
395 }
396 }
397
398 pub fn benchmark_gas_keys(n: usize) -> Vec<IotaKeyPair> {
403 let mut rng = StdRng::seed_from_u64(Self::BENCHMARKS_RNG_SEED);
404 (0..n)
405 .map(|_| IotaKeyPair::Ed25519(NetworkKeyPair::generate(&mut rng)))
406 .collect()
407 }
408
409 pub fn add_faucet_account(mut self) -> Self {
410 self.accounts.push(AccountConfig {
411 address: None,
412 gas_amounts: vec![DEFAULT_GAS_AMOUNT; DEFAULT_NUMBER_OF_OBJECT_PER_ACCOUNT],
413 });
414 self
415 }
416
417 pub fn add_delegator(mut self, address: IotaAddress) -> Self {
418 self.delegator = Some(address);
419 self
420 }
421}