From 44fde2d9648bcd452b504b0340f1027a10b54d4b Mon Sep 17 00:00:00 2001 From: Grimes <39311140+solana-grimes@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:42:01 -0800 Subject: [PATCH] genesis: Add support for multiple bootstrap validators (#8656) automerge --- genesis/src/main.rs | 166 +++++++++++--------------- multinode-demo/bootstrap-validator.sh | 3 - multinode-demo/setup.sh | 14 +-- run.sh | 15 +-- 4 files changed, 79 insertions(+), 119 deletions(-) diff --git a/genesis/src/main.rs b/genesis/src/main.rs index 523a90a88..4551a75cb 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -2,8 +2,8 @@ use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches}; use solana_clap_utils::{ - input_parsers::{pubkey_of, unix_timestamp_from_rfc3339_datetime}, - input_validators::{is_rfc3339_datetime, is_valid_percentage}, + input_parsers::{pubkey_of, pubkeys_of, unix_timestamp_from_rfc3339_datetime}, + input_validators::{is_pubkey_or_keypair, is_rfc3339_datetime, is_valid_percentage}, }; use solana_genesis::{genesis_accounts::add_genesis_accounts, Base64Account}; use solana_ledger::{blockstore::create_new_ledger, poh::compute_hashes_per_tick}; @@ -21,16 +21,9 @@ use solana_sdk::{ system_program, timing, }; use solana_stake_program::stake_state::{self, StakeState}; -use solana_storage_program::storage_contract; use solana_vote_program::vote_state::{self, VoteState}; use std::{ - collections::{BTreeMap, HashMap}, - error, - fs::File, - io, - path::PathBuf, - str::FromStr, - time::Duration, + collections::HashMap, error, fs::File, io, path::PathBuf, process, str::FromStr, time::Duration, }; pub enum AccountFileFormat { @@ -38,16 +31,6 @@ pub enum AccountFileFormat { Keypair, } -fn required_pubkey(matches: &ArgMatches<'_>, name: &str) -> Result> { - pubkey_of(matches, name).ok_or_else(|| { - format!( - "Invalid pubkey or file: {}", - matches.value_of(name).unwrap() - ) - .into() - }) -} - fn pubkey_from_str(key_str: &str) -> Result> { Pubkey::from_str(key_str).or_else(|_| { let bytes: Vec = serde_json::from_str(key_str)?; @@ -151,13 +134,16 @@ fn main() -> Result<(), Box> { .help("Time when the bootstrap validator will start the cluster [default: current system time]"), ) .arg( - Arg::with_name("bootstrap_validator_pubkey_file") + Arg::with_name("bootstrap_validator") .short("b") - .long("bootstrap-validator-pubkey") - .value_name("BOOTSTRAP VALIDATOR PUBKEY") + .long("bootstrap-validator") + .value_name("IDENTITY_PUBKEY VOTE_PUBKEY STAKE_PUBKEY") .takes_value(true) + .validator(is_pubkey_or_keypair) + .number_of_values(3) + .multiple(true) .required(true) - .help("Path to file containing the bootstrap validator's pubkey"), + .help("The bootstrap validator's identity, vote and stake pubkeys"), ) .arg( Arg::with_name("ledger_path") @@ -174,58 +160,36 @@ fn main() -> Result<(), Box> { .long("faucet-lamports") .value_name("LAMPORTS") .takes_value(true) - .requires("faucet_pubkey_file") + .requires("faucet_pubkey") .help("Number of lamports to assign to the faucet"), ) .arg( - Arg::with_name("faucet_pubkey_file") + Arg::with_name("faucet_pubkey") .short("m") .long("faucet-pubkey") .value_name("PUBKEY") .takes_value(true) + .validator(is_pubkey_or_keypair) .requires("faucet_lamports") .help("Path to file containing the faucet's pubkey"), ) .arg( - Arg::with_name("bootstrap_vote_pubkey_file") - .long("bootstrap-vote-pubkey") - .value_name("BOOTSTRAP VOTE PUBKEY") - .takes_value(true) - .required(true) - .help("Path to file containing the bootstrap validator's voting pubkey"), - ) - .arg( - Arg::with_name("bootstrap_stake_pubkey_file") - .long("bootstrap-stake-pubkey") - .value_name("BOOTSTRAP STAKE PUBKEY") - .takes_value(true) - .required(true) - .help("Path to file containing the bootstrap validator's staking pubkey"), - ) - .arg( - Arg::with_name("bootstrap_stake_authorized_pubkey_file") + Arg::with_name("bootstrap_stake_authorized_pubkey") .long("bootstrap-stake-authorized-pubkey") .value_name("BOOTSTRAP STAKE AUTHORIZED PUBKEY") .takes_value(true) + .validator(is_pubkey_or_keypair) .help( "Path to file containing the pubkey authorized to manage the bootstrap \ validator's stake [default: --bootstrap-validator-pubkey]", ), ) - .arg( - Arg::with_name("bootstrap_storage_pubkey_file") - .long("bootstrap-storage-pubkey") - .value_name("BOOTSTRAP STORAGE PUBKEY") - .takes_value(true) - .help("Path to file containing the bootstrap validator's storage pubkey"), - ) .arg( Arg::with_name("bootstrap_validator_lamports") .long("bootstrap-validator-lamports") .value_name("LAMPORTS") .takes_value(true) .default_value(default_bootstrap_validator_lamports) - .required(true) .help("Number of lamports to assign to the bootstrap validator"), ) .arg( @@ -234,7 +198,6 @@ fn main() -> Result<(), Box> { .value_name("LAMPORTS") .takes_value(true) .default_value(default_bootstrap_validator_stake_lamports) - .required(true) .help("Number of lamports to assign to the bootstrap validator's stake account"), ) .arg( @@ -391,6 +354,20 @@ fn main() -> Result<(), Box> { } } + let bootstrap_validator_pubkeys = pubkeys_of(&matches, "bootstrap_validator").unwrap(); + assert_eq!(bootstrap_validator_pubkeys.len() % 3, 0); + + // Ensure there are no duplicated pubkeys in the --bootstrap-validator list + { + let mut v = bootstrap_validator_pubkeys.clone(); + v.sort(); + v.dedup(); + if v.len() != bootstrap_validator_pubkeys.len() { + eprintln!("Error: --bootstrap-validator pubkeys cannot be duplicated"); + process::exit(1); + } + } + let bootstrap_validator_lamports = value_t_or_exit!(matches, "bootstrap_validator_lamports", u64); @@ -400,52 +377,9 @@ fn main() -> Result<(), Box> { StakeState::get_rent_exempt_reserve(&rent), )?; - let bootstrap_validator_pubkey = required_pubkey(&matches, "bootstrap_validator_pubkey_file")?; - let bootstrap_vote_pubkey = required_pubkey(&matches, "bootstrap_vote_pubkey_file")?; - let bootstrap_stake_pubkey = required_pubkey(&matches, "bootstrap_stake_pubkey_file")?; let bootstrap_stake_authorized_pubkey = - pubkey_of(&matches, "bootstrap_stake_authorized_pubkey_file"); - let bootstrap_storage_pubkey = pubkey_of(&matches, "bootstrap_storage_pubkey_file"); - let faucet_pubkey = pubkey_of(&matches, "faucet_pubkey_file"); - - let bootstrap_validator_vote_account = vote_state::create_account( - &bootstrap_vote_pubkey, - &bootstrap_validator_pubkey, - 100, - VoteState::get_rent_exempt_reserve(&rent).max(1), - ); - - let bootstrap_validator_stake_account = stake_state::create_account( - bootstrap_stake_authorized_pubkey - .as_ref() - .unwrap_or(&bootstrap_validator_pubkey), - &bootstrap_vote_pubkey, - &bootstrap_validator_vote_account, - &rent, - bootstrap_validator_stake_lamports, - ); - - let mut accounts: BTreeMap = [ - // node needs an account to issue votes from - ( - bootstrap_validator_pubkey, - Account::new(bootstrap_validator_lamports, 0, &system_program::id()), - ), - // where votes go to - (bootstrap_vote_pubkey, bootstrap_validator_vote_account), - // bootstrap validator stake - (bootstrap_stake_pubkey, bootstrap_validator_stake_account), - ] - .iter() - .cloned() - .collect(); - - if let Some(bootstrap_storage_pubkey) = bootstrap_storage_pubkey { - accounts.insert( - bootstrap_storage_pubkey, - storage_contract::create_validator_storage_account(bootstrap_validator_pubkey, 1), - ); - } + pubkey_of(&matches, "bootstrap_stake_authorized_pubkey"); + let faucet_pubkey = pubkey_of(&matches, "faucet_pubkey"); let ticks_per_slot = value_t_or_exit!(matches, "ticks_per_slot", u64); @@ -508,7 +442,6 @@ fn main() -> Result<(), Box> { let inflation = solana_genesis_programs::get_inflation(operating_mode, 0).unwrap(); let mut genesis_config = GenesisConfig { - accounts, native_instruction_processors, ticks_per_slot, epoch_schedule, @@ -520,6 +453,43 @@ fn main() -> Result<(), Box> { ..GenesisConfig::default() }; + let mut bootstrap_validator_pubkeys_iter = bootstrap_validator_pubkeys.iter(); + loop { + let identity_pubkey = match bootstrap_validator_pubkeys_iter.next() { + None => break, + Some(identity_pubkey) => identity_pubkey, + }; + let vote_pubkey = bootstrap_validator_pubkeys_iter.next().unwrap(); + let stake_pubkey = bootstrap_validator_pubkeys_iter.next().unwrap(); + + genesis_config.add_account( + *identity_pubkey, + Account::new(bootstrap_validator_lamports, 0, &system_program::id()), + ); + + let vote_account = vote_state::create_account( + &vote_pubkey, + &identity_pubkey, + 100, + VoteState::get_rent_exempt_reserve(&rent).max(1), + ); + + genesis_config.add_account( + *stake_pubkey, + stake_state::create_account( + bootstrap_stake_authorized_pubkey + .as_ref() + .unwrap_or(&identity_pubkey), + &vote_pubkey, + &vote_account, + &rent, + bootstrap_validator_stake_lamports, + ), + ); + + genesis_config.add_account(*vote_pubkey, vote_account); + } + if let Some(creation_time) = unix_timestamp_from_rfc3339_datetime(&matches, "creation_time") { genesis_config.creation_time = creation_time; } diff --git a/multinode-demo/bootstrap-validator.sh b/multinode-demo/bootstrap-validator.sh index 19a9d1f6b..fe085fc66 100755 --- a/multinode-demo/bootstrap-validator.sh +++ b/multinode-demo/bootstrap-validator.sh @@ -66,7 +66,6 @@ done # These keypairs are created by ./setup.sh and included in the genesis config identity_keypair=$SOLANA_CONFIG_DIR/bootstrap-validator/identity-keypair.json vote_keypair="$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-keypair.json -storage_keypair=$SOLANA_CONFIG_DIR/bootstrap-validator/storage-keypair.json ledger_dir="$SOLANA_CONFIG_DIR"/bootstrap-validator [[ -d "$ledger_dir" ]] || { @@ -82,7 +81,6 @@ args+=( --rpc-port 8899 --snapshot-interval-slots 100 --identity-keypair "$identity_keypair" - --storage-keypair "$storage_keypair" --voting-keypair "$vote_keypair" --rpc-faucet-address 127.0.0.1:9900 ) @@ -90,7 +88,6 @@ default_arg --gossip-port 8001 default_arg --log - - pid= kill_node() { # Note: do not echo anything from this function to ensure $pid is actually diff --git a/multinode-demo/setup.sh b/multinode-demo/setup.sh index ebb8ac8d8..dec27c9b1 100755 --- a/multinode-demo/setup.sh +++ b/multinode-demo/setup.sh @@ -24,14 +24,14 @@ fi $solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-keypair.json $solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-keypair.json -$solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/storage-keypair.json -args=("$@") -default_arg --enable-warmup-epochs -default_arg --bootstrap-validator-pubkey "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity-keypair.json -default_arg --bootstrap-vote-pubkey "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-keypair.json -default_arg --bootstrap-stake-pubkey "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-keypair.json -default_arg --bootstrap-storage-pubkey "$SOLANA_CONFIG_DIR"/bootstrap-validator/storage-keypair.json +args=( + "$@" + --enable-warmup-epochs + --bootstrap-validator "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity-keypair.json + "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-keypair.json + "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-keypair.json +) default_arg --ledger "$SOLANA_CONFIG_DIR"/bootstrap-validator default_arg --faucet-pubkey "$SOLANA_CONFIG_DIR"/faucet-keypair.json default_arg --faucet-lamports 500000000000000000 diff --git a/run.sh b/run.sh index d93792c70..047c5b433 100755 --- a/run.sh +++ b/run.sh @@ -70,12 +70,6 @@ if [[ -e $faucet_keypair ]]; then else solana-keygen new --no-passphrase -fso "$faucet_keypair" fi -leader_storage_account_keypair="$dataDir"/leader-storage-account-keypair.json -if [[ -e $leader_storage_account_keypair ]]; then - echo "Use existing leader storage account keypair" -else - solana-keygen new --no-passphrase -fso "$leader_storage_account_keypair" -fi if [[ -e "$ledgerDir"/genesis.bin ]]; then echo "Use existing genesis" @@ -84,10 +78,10 @@ else --hashes-per-tick sleep \ --faucet-pubkey "$dataDir"/faucet-keypair.json \ --faucet-lamports 500000000000000000 \ - --bootstrap-validator-pubkey "$dataDir"/leader-keypair.json \ - --bootstrap-vote-pubkey "$dataDir"/leader-vote-account-keypair.json \ - --bootstrap-stake-pubkey "$dataDir"/leader-stake-account-keypair.json \ - --bootstrap-storage-pubkey "$dataDir"/leader-storage-account-keypair.json \ + --bootstrap-validator \ + "$dataDir"/leader-keypair.json \ + "$dataDir"/leader-vote-account-keypair.json \ + "$dataDir"/leader-stake-account-keypair.json \ --ledger "$ledgerDir" \ --operating-mode development fi @@ -104,7 +98,6 @@ faucet=$! args=( --identity-keypair "$dataDir"/leader-keypair.json - --storage-keypair "$dataDir"/leader-storage-account-keypair.json --voting-keypair "$dataDir"/leader-vote-account-keypair.json --ledger "$ledgerDir" --gossip-port 8001