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