Kaynağa Gözat

(Alpenglow) Add Alpenglow mode in genesis. (#8482)

* (Alpenglow) Add Alpenglow mode in genesis.

* Fix genesis test and remove TODO.

* Make linter happy.

* Use the new stake_state::create_account.

* Fix a bad merge.

* Fix a bad merge.

* Add the dev-bins Cargo.lock change.

* We actually should allow specifying BLS pubkeys in TowerBFT so we can test Migration.

* Change bls_pubkeys to bls_pubkeys_iter.
Wen 3 hafta önce
ebeveyn
işleme
28c8acc544

+ 4 - 0
Cargo.lock

@@ -7528,6 +7528,7 @@ dependencies = [
  "chrono",
  "clap 2.33.3",
  "rpassword",
+ "solana-bls-signatures",
  "solana-clock",
  "solana-cluster-type",
  "solana-commitment-config",
@@ -8561,6 +8562,7 @@ dependencies = [
  "serde_json",
  "serde_yaml 0.9.34+deprecated",
  "solana-account",
+ "solana-bls-signatures",
  "solana-borsh",
  "solana-clap-utils",
  "solana-cli-config",
@@ -8591,8 +8593,10 @@ dependencies = [
  "solana-stake-program",
  "solana-time-utils",
  "solana-version",
+ "solana-vote",
  "solana-vote-program",
  "tempfile",
+ "test-case",
 ]
 
 [[package]]

+ 1 - 0
clap-utils/Cargo.toml

@@ -22,6 +22,7 @@ agave-unstable-api = []
 chrono = { workspace = true, features = ["default"] }
 clap = "2.33.0"
 rpassword = { workspace = true }
+solana-bls-signatures = { workspace = true }
 solana-clock = { workspace = true }
 solana-cluster-type = { workspace = true }
 solana-commitment-config = { workspace = true }

+ 31 - 0
clap-utils/src/input_parsers.rs

@@ -5,6 +5,7 @@ use {
     },
     chrono::DateTime,
     clap::ArgMatches,
+    solana_bls_signatures::Pubkey as BLSPubkey,
     solana_clock::UnixTimestamp,
     solana_cluster_type::ClusterType,
     solana_commitment_config::CommitmentConfig,
@@ -104,6 +105,18 @@ pub fn pubkeys_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Pubkey>> {
     })
 }
 
+pub fn bls_pubkeys_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<BLSPubkey>> {
+    matches.values_of(name).map(|values| {
+        values
+            .map(|value| {
+                BLSPubkey::from_str(value).unwrap_or_else(|_| {
+                    panic!("Failed to parse BLS public key from value: {value}")
+                })
+            })
+            .collect()
+    })
+}
+
 // Return pubkey/signature pairs for a string of the form pubkey=signature
 pub fn pubkeys_sigs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<(Pubkey, Signature)>> {
     matches.values_of(name).map(|values| {
@@ -253,6 +266,7 @@ mod tests {
     use {
         super::*,
         clap::{App, Arg},
+        solana_bls_signatures::{keypair::Keypair as BLSKeypair, Pubkey as BLSPubkey},
         solana_keypair::write_keypair_file,
         std::fs,
     };
@@ -416,6 +430,23 @@ mod tests {
         assert_ne!(lamports_of_sol(&matches, "single"), Some(502_500_000));
     }
 
+    #[test]
+    fn test_bls_pubkeys_of() {
+        let bls_pubkey1: BLSPubkey = BLSKeypair::new().public;
+        let bls_pubkey2: BLSPubkey = BLSKeypair::new().public;
+        let matches = app().get_matches_from(vec![
+            "test",
+            "--multiple",
+            &bls_pubkey1.to_string(),
+            "--multiple",
+            &bls_pubkey2.to_string(),
+        ]);
+        assert_eq!(
+            bls_pubkeys_of(&matches, "multiple"),
+            Some(vec![bls_pubkey1, bls_pubkey2])
+        );
+    }
+
     #[test]
     fn test_lamports_of_sol() {
         let matches = app().get_matches_from(vec!["test", "--single", "50"]);

+ 2 - 0
dev-bins/Cargo.lock

@@ -6453,6 +6453,7 @@ dependencies = [
  "chrono",
  "clap 2.34.0",
  "rpassword",
+ "solana-bls-signatures",
  "solana-clock",
  "solana-cluster-type",
  "solana-commitment-config",
@@ -7192,6 +7193,7 @@ dependencies = [
  "serde_json",
  "serde_yaml",
  "solana-account",
+ "solana-bls-signatures",
  "solana-clap-utils",
  "solana-cli-config",
  "solana-clock",

+ 3 - 0
genesis/Cargo.toml

@@ -35,6 +35,7 @@ serde = { workspace = true }
 serde_json = { workspace = true }
 serde_yaml = { workspace = true }
 solana-account = "=3.1.0"
+solana-bls-signatures = { workspace = true }
 solana-clap-utils = { workspace = true }
 solana-cli-config = { workspace = true }
 solana-clock = "=3.0.0"
@@ -71,3 +72,5 @@ solana-borsh = { workspace = true }
 solana-genesis = { path = ".", features = ["agave-unstable-api"] }
 solana-pubkey = { workspace = true, features = ["rand"] }
 solana-runtime = { workspace = true, features = ["dev-context-only-utils"] }
+solana-vote = { workspace = true }
+test-case = { workspace = true }

+ 1 - 0
genesis/src/lib.rs

@@ -38,4 +38,5 @@ pub struct StakedValidatorAccountInfo {
     pub identity_account: String,
     pub vote_account: String,
     pub stake_account: String,
+    pub bls_pubkey: Option<String>,
 }

+ 84 - 14
genesis/src/main.rs

@@ -7,9 +7,11 @@ use {
     clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches},
     itertools::Itertools,
     solana_account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
+    solana_bls_signatures::Pubkey as BLSPubkey,
     solana_clap_utils::{
         input_parsers::{
-            cluster_type_of, pubkey_of, pubkeys_of, unix_timestamp_from_rfc3339_datetime,
+            bls_pubkeys_of, cluster_type_of, pubkey_of, pubkeys_of,
+            unix_timestamp_from_rfc3339_datetime,
         },
         input_validators::{
             is_pubkey, is_pubkey_or_keypair, is_rfc3339_datetime, is_slot, is_url_or_moniker,
@@ -39,6 +41,7 @@ use {
     solana_rent::Rent,
     solana_rpc_client::rpc_client::RpcClient,
     solana_rpc_client_api::request::MAX_MULTIPLE_ACCOUNTS,
+    solana_runtime::genesis_utils::bls_pubkey_to_compressed_bytes,
     solana_sdk_ids::system_program,
     solana_signer::Signer,
     solana_stake_interface::state::StakeStateV2,
@@ -144,10 +147,16 @@ pub fn load_validator_accounts(
                 ))
             })?,
         ];
+        let bls_pubkeys: Vec<BLSPubkey> = account_details.bls_pubkey.map_or(Ok(vec![]), |s| {
+            BLSPubkey::from_str(&s).map(|pk| vec![pk]).map_err(|err| {
+                io::Error::new(io::ErrorKind::Other, format!("Invalid BLS pubkey: {err}"))
+            })
+        })?;
 
         add_validator_accounts(
             genesis_config,
             &mut pubkeys.iter(),
+            &mut bls_pubkeys.iter(),
             account_details.balance_lamports,
             account_details.stake_lamports,
             commission,
@@ -226,6 +235,7 @@ fn features_to_deactivate_for_cluster(
 fn add_validator_accounts(
     genesis_config: &mut GenesisConfig,
     pubkeys_iter: &mut Iter<Pubkey>,
+    bls_pubkeys_iter: &mut Iter<BLSPubkey>,
     lamports: u64,
     stake_lamports: u64,
     commission: u8,
@@ -249,11 +259,13 @@ fn add_validator_accounts(
             AccountSharedData::new(lamports, 0, &system_program::id()),
         );
 
+        let bls_pubkey_compressed_bytes =
+            bls_pubkeys_iter.next().map(bls_pubkey_to_compressed_bytes);
         let vote_account = vote_state::create_v4_account_with_authorized(
             identity_pubkey,
             identity_pubkey,
             identity_pubkey,
-            None,
+            bls_pubkey_compressed_bytes,
             u16::from(commission) * 100,
             rent.minimum_balance(VoteStateV4::size_of()).max(1),
         );
@@ -353,6 +365,15 @@ fn main() -> Result<(), Box<dyn error::Error>> {
                 .required(true)
                 .help("The bootstrap validator's identity, vote and stake pubkeys"),
         )
+        .arg(
+            Arg::with_name("bootstrap_validator_bls_pubkey")
+                .long("bootstrap-validator-bls-pubkey")
+                .value_name("BLS_PUBKEY")
+                .multiple(true)
+                .takes_value(true)
+                .required(false)
+                .help("The bootstrap validator's bls pubkey"),
+        )
         .arg(
             Arg::with_name("ledger_path")
                 .short("l")
@@ -614,6 +635,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
                      testnet, devnet, localhost]. Used for cloning feature sets",
                 ),
         )
+        .arg(
+            Arg::with_name("alpenglow")
+                .long("alpenglow")
+                .help("Whether we use Alpenglow consensus."),
+        )
         .get_matches();
 
     let ledger_path = PathBuf::from(matches.value_of("ledger_path").unwrap());
@@ -627,6 +653,16 @@ fn main() -> Result<(), Box<dyn error::Error>> {
     let bootstrap_validator_pubkeys = pubkeys_of(&matches, "bootstrap_validator").unwrap();
     assert_eq!(bootstrap_validator_pubkeys.len() % 3, 0);
 
+    let bootstrap_validator_bls_pubkeys =
+        bls_pubkeys_of(&matches, "bootstrap_validator_bls_pubkey");
+    if let Some(bls_pubkeys) = &bootstrap_validator_bls_pubkeys {
+        assert_eq!(
+            bls_pubkeys.len() * 3,
+            bootstrap_validator_pubkeys.len(),
+            "Number of BLS pubkeys must match the number of bootstrap validator identities"
+        );
+    }
+
     // Ensure there are no duplicated pubkeys in the --bootstrap-validator list
     {
         let mut v = bootstrap_validator_pubkeys.clone();
@@ -733,9 +769,12 @@ fn main() -> Result<(), Box<dyn error::Error>> {
     let commission = value_t_or_exit!(matches, "vote_commission_percentage", u8);
     let rent = genesis_config.rent.clone();
 
+    let is_alpenglow = matches.is_present("alpenglow");
+
     add_validator_accounts(
         &mut genesis_config,
         &mut bootstrap_validator_pubkeys.iter(),
+        &mut bootstrap_validator_bls_pubkeys.unwrap_or_default().iter(),
         bootstrap_validator_lamports,
         bootstrap_validator_stake_lamports,
         commission,
@@ -755,7 +794,13 @@ fn main() -> Result<(), Box<dyn error::Error>> {
     }
 
     solana_stake_program::add_genesis_accounts(&mut genesis_config);
-    solana_runtime::genesis_utils::activate_all_features(&mut genesis_config);
+
+    if is_alpenglow {
+        solana_runtime::genesis_utils::activate_all_features_alpenglow(&mut genesis_config);
+    } else {
+        solana_runtime::genesis_utils::activate_all_features(&mut genesis_config);
+    }
+
     if !features_to_deactivate.is_empty() {
         solana_runtime::genesis_utils::deactivate_features(
             &mut genesis_config,
@@ -894,10 +939,12 @@ fn main() -> Result<(), Box<dyn error::Error>> {
 mod tests {
     use {
         super::*,
+        solana_bls_signatures::keypair::Keypair as BLSKeypair,
         solana_borsh::v1 as borsh1,
         solana_genesis_config::GenesisConfig,
         solana_stake_interface as stake,
         std::{collections::HashMap, fs::remove_file, io::Write, path::Path},
+        test_case::test_case,
     };
 
     #[test]
@@ -1247,24 +1294,34 @@ mod tests {
         assert_eq!(genesis_config.accounts.len(), 3);
     }
 
-    #[test]
-    fn test_append_validator_accounts_to_genesis() {
+    #[test_case(true; "add bls pubkey")]
+    #[test_case(false; "no bls pubkey")]
+    // It's wrong to have (true, false) combination, Alpenglow requires BLS keys
+    fn test_append_validator_accounts_to_genesis(add_bls_pubkey: bool) {
         // Test invalid file returns error
         assert!(load_validator_accounts(
             "unknownfile",
             100,
             &Rent::default(),
-            &mut GenesisConfig::default()
+            &mut GenesisConfig::default(),
         )
         .is_err());
 
         let mut genesis_config = GenesisConfig::default();
 
+        let generate_bls_pubkey = || {
+            if add_bls_pubkey {
+                Some(BLSKeypair::new().public.to_string())
+            } else {
+                None
+            }
+        };
         let validator_accounts = vec![
             StakedValidatorAccountInfo {
                 identity_account: solana_pubkey::new_rand().to_string(),
                 vote_account: solana_pubkey::new_rand().to_string(),
                 stake_account: solana_pubkey::new_rand().to_string(),
+                bls_pubkey: generate_bls_pubkey(),
                 balance_lamports: 100000000000,
                 stake_lamports: 10000000000,
             },
@@ -1272,6 +1329,7 @@ mod tests {
                 identity_account: solana_pubkey::new_rand().to_string(),
                 vote_account: solana_pubkey::new_rand().to_string(),
                 stake_account: solana_pubkey::new_rand().to_string(),
+                bls_pubkey: generate_bls_pubkey(),
                 balance_lamports: 200000000000,
                 stake_lamports: 20000000000,
             },
@@ -1279,6 +1337,7 @@ mod tests {
                 identity_account: solana_pubkey::new_rand().to_string(),
                 vote_account: solana_pubkey::new_rand().to_string(),
                 stake_account: solana_pubkey::new_rand().to_string(),
+                bls_pubkey: generate_bls_pubkey(),
                 balance_lamports: 300000000000,
                 stake_lamports: 30000000000,
             },
@@ -1287,18 +1346,18 @@ mod tests {
         let serialized = serde_yaml::to_string(&validator_accounts).unwrap();
 
         // write accounts to file
-        let path = Path::new("test_append_validator_accounts_to_genesis.yml");
+        let filename = if add_bls_pubkey {
+            "test_append_validator_accounts_to_genesis_with_bls.yml"
+        } else {
+            "test_append_validator_accounts_to_genesis_without_bls.yml"
+        };
+        let path = Path::new(filename);
         let mut file = File::create(path).unwrap();
         file.write_all(b"validator_accounts:\n").unwrap();
         file.write_all(serialized.as_bytes()).unwrap();
 
-        load_validator_accounts(
-            "test_append_validator_accounts_to_genesis.yml",
-            100,
-            &Rent::default(),
-            &mut genesis_config,
-        )
-        .expect("Failed to load validator accounts");
+        load_validator_accounts(filename, 100, &Rent::default(), &mut genesis_config)
+            .expect("Failed to load validator accounts");
 
         remove_file(path).unwrap();
 
@@ -1328,6 +1387,17 @@ mod tests {
                 assert_eq!(vote_state.authorized_withdrawer, identity_pk);
                 let authorized_voters = &vote_state.authorized_voters;
                 assert_eq!(authorized_voters.first().unwrap().1, &identity_pk);
+                if add_bls_pubkey {
+                    assert_eq!(
+                        bls_pubkey_to_compressed_bytes(
+                            &BLSPubkey::from_str(b64_account.bls_pubkey.as_ref().unwrap()).unwrap()
+                        ),
+                        vote_state.bls_pubkey_compressed.unwrap()
+                    );
+                } else {
+                    assert!(b64_account.bls_pubkey.is_none());
+                    assert!(vote_state.bls_pubkey_compressed.is_none());
+                }
 
                 // check stake account
                 let stake_pk = b64_account.stake_account.parse().unwrap();

+ 1 - 0
programs/sbf/Cargo.lock

@@ -6280,6 +6280,7 @@ dependencies = [
  "chrono",
  "clap",
  "rpassword",
+ "solana-bls-signatures",
  "solana-clock",
  "solana-cluster-type",
  "solana-commitment-config",