Joe C преди 7 месеца
родител
ревизия
c7d7987d58

+ 21 - 27
Cargo.lock

@@ -180,7 +180,7 @@ dependencies = [
  "serde_yaml 0.8.26",
  "serde_yaml 0.9.34+deprecated",
  "solana-clap-utils",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-hash",
  "solana-keypair",
  "solana-logger",
@@ -3877,6 +3877,16 @@ dependencies = [
  "unicase",
 ]
 
+[[package]]
+name = "kaigan"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ba15de5aeb137f0f65aa3bf82187647f1285abfe5b20c80c2c37f7007ad519a"
+dependencies = [
+ "borsh 0.10.3",
+ "serde",
+]
+
 [[package]]
 name = "keccak"
 version = "0.1.5"
@@ -6399,7 +6409,7 @@ dependencies = [
  "solana-account",
  "solana-account-decoder-client-types",
  "solana-clock",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-epoch-schedule",
  "solana-fee-calculator",
  "solana-hash",
@@ -6980,7 +6990,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-loader-v4-program",
  "solana-program-runtime",
  "solana-pubkey",
@@ -7004,7 +7013,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-frozen-abi",
  "solana-loader-v4-program",
  "solana-pubkey",
@@ -7147,7 +7155,7 @@ dependencies = [
  "solana-commitment-config",
  "solana-compute-budget",
  "solana-compute-budget-interface",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-connection-cache",
  "solana-decode-error",
  "solana-epoch-schedule",
@@ -7472,28 +7480,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "solana-config-program"
-version = "2.3.0"
+name = "solana-config-program-client"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53aceac36f105fd4922e29b4f0c1f785b69d7b3e7e387e384b8985c8e0c3595e"
 dependencies = [
  "bincode",
- "chrono",
+ "borsh 0.10.3",
+ "kaigan",
  "serde",
- "serde_derive",
- "solana-account",
- "solana-bincode",
- "solana-instruction",
- "solana-keypair",
- "solana-log-collector",
- "solana-logger",
- "solana-packet",
- "solana-program-runtime",
- "solana-pubkey",
- "solana-sdk-ids",
- "solana-short-vec",
- "solana-signer",
- "solana-stake-interface",
- "solana-system-interface",
- "solana-transaction-context 2.3.0",
+ "solana-program",
 ]
 
 [[package]]
@@ -8603,7 +8599,6 @@ dependencies = [
  "serial_test",
  "solana-accounts-db",
  "solana-client",
- "solana-config-program",
  "solana-core",
  "solana-download-utils",
  "solana-entry",
@@ -9709,7 +9704,6 @@ dependencies = [
  "solana-builtins",
  "solana-compute-budget",
  "solana-compute-budget-instruction",
- "solana-config-program",
  "solana-cost-model",
  "solana-fee",
  "solana-frozen-abi",
@@ -10173,7 +10167,7 @@ dependencies = [
  "solana-bincode",
  "solana-clock",
  "solana-compute-budget",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-epoch-rewards",
  "solana-epoch-schedule",
  "solana-genesis-config",

+ 1 - 2
Cargo.toml

@@ -94,7 +94,6 @@ members = [
     "programs/bpf_loader/gen-syscall-list",
     "programs/compute-budget",
     "programs/compute-budget-bench",
-    "programs/config",
     "programs/ed25519-tests",
     "programs/loader-v4",
     "programs/stake",
@@ -406,7 +405,7 @@ solana-compute-budget = { path = "compute-budget", version = "=2.3.0" }
 solana-compute-budget-instruction = { path = "compute-budget-instruction", version = "=2.3.0" }
 solana-compute-budget-interface = "2.2.1"
 solana-compute-budget-program = { path = "programs/compute-budget", version = "=2.3.0" }
-solana-config-program = { path = "programs/config", version = "=2.3.0" }
+solana-config-program-client = "0.0.2"
 solana-connection-cache = { path = "connection-cache", version = "=2.3.0", default-features = false }
 solana-core = { path = "core", version = "=2.3.0" }
 solana-cost-model = { path = "cost-model", version = "=2.3.0" }

+ 2 - 1
account-decoder/Cargo.toml

@@ -22,7 +22,7 @@ serde_json = { workspace = true }
 solana-account = { workspace = true }
 solana-account-decoder-client-types = { workspace = true, features = ["zstd"] }
 solana-clock = { workspace = true }
-solana-config-program = { workspace = true }
+solana-config-program-client = { workspace = true, features = ["serde"] }
 solana-epoch-schedule = { workspace = true }
 solana-fee-calculator = { workspace = true }
 solana-instruction = { workspace = true }
@@ -45,6 +45,7 @@ zstd = { workspace = true }
 
 [dev-dependencies]
 assert_matches = { workspace = true }
+solana-account = { workspace = true, features = ["bincode"] }
 solana-hash = { workspace = true }
 solana-program = { workspace = true, default-features = false }
 solana-pubkey = { workspace = true, features = ["rand"] }

+ 22 - 3
account-decoder/src/parse_config.rs

@@ -5,7 +5,7 @@ use {
     },
     bincode::deserialize,
     serde_json::Value,
-    solana_config_program::{get_config_data, ConfigKeys},
+    solana_config_program_client::{get_config_data, ConfigKeys},
     solana_program::stake::config::{
         Config as StakeConfig, {self as stake_config},
     },
@@ -96,10 +96,29 @@ pub struct UiConfig<T> {
 #[cfg(test)]
 mod test {
     use {
-        super::*, crate::validator_info::ValidatorInfo, serde_json::json,
-        solana_account::ReadableAccount, solana_config_program::create_config_account,
+        super::*,
+        crate::validator_info::ValidatorInfo,
+        bincode::serialize,
+        serde_json::json,
+        solana_account::{Account, AccountSharedData, ReadableAccount},
+        solana_config_program_client::ConfigKeys,
     };
 
+    fn create_config_account<T: serde::Serialize>(
+        keys: Vec<(Pubkey, bool)>,
+        config_data: &T,
+        lamports: u64,
+    ) -> AccountSharedData {
+        let mut data = serialize(&ConfigKeys { keys }).unwrap();
+        data.extend_from_slice(&serialize(config_data).unwrap());
+        AccountSharedData::from(Account {
+            lamports,
+            data,
+            owner: solana_sdk_ids::config::id(),
+            ..Account::default()
+        })
+    }
+
     #[test]
     fn test_parse_config() {
         let stake_config = StakeConfig {

+ 1 - 1
account-decoder/src/validator_info.rs

@@ -1,4 +1,4 @@
-use solana_config_program::ConfigState;
+use solana_config_program_client::instructions_bincode::ConfigState;
 
 pub const MAX_SHORT_FIELD_LENGTH: usize = 80;
 pub const MAX_LONG_FIELD_LENGTH: usize = 300;

+ 0 - 1
builtins-default-costs/Cargo.toml

@@ -17,7 +17,6 @@ log = { workspace = true }
 solana-address-lookup-table-program = { workspace = true }
 solana-bpf-loader-program = { workspace = true }
 solana-compute-budget-program = { workspace = true }
-solana-config-program = { workspace = true }
 solana-frozen-abi = { workspace = true, optional = true, features = [
     "frozen-abi",
 ] }

+ 3 - 26
builtins-default-costs/src/lib.rs

@@ -7,8 +7,7 @@ use {
     solana_pubkey::Pubkey,
     solana_sdk_ids::{
         address_lookup_table, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
-        compute_budget, config, ed25519_program, loader_v4, secp256k1_program, stake,
-        system_program, vote,
+        compute_budget, ed25519_program, loader_v4, secp256k1_program, stake, system_program, vote,
     },
 };
 
@@ -102,7 +101,7 @@ lazy_static! {
 /// correctly furnishing `core_bpf_migration_feature`.
 ///
 #[allow(dead_code)]
-const TOTAL_COUNT_BUILTINS: usize = 12;
+const TOTAL_COUNT_BUILTINS: usize = 11;
 #[cfg(test)]
 static_assertions::const_assert_eq!(
     MIGRATING_BUILTINS_COSTS.len() + NON_MIGRATING_BUILTINS_COSTS.len(),
@@ -118,21 +117,13 @@ pub const MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[
             position: 0,
         }),
     ),
-    (
-        config::id(),
-        BuiltinCost::Migrating(MigratingBuiltinCost {
-            native_cost: solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS,
-            core_bpf_migration_feature: feature_set::migrate_config_program_to_core_bpf::id(),
-            position: 1,
-        }),
-    ),
     (
         address_lookup_table::id(),
         BuiltinCost::Migrating(MigratingBuiltinCost {
             native_cost: solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS,
             core_bpf_migration_feature:
                 feature_set::migrate_address_lookup_table_program_to_core_bpf::id(),
-            position: 2,
+            position: 1,
         }),
     ),
 ];
@@ -340,20 +331,6 @@ mod test {
             get_migration_feature_id(feature_index),
             &feature_set::migrate_stake_program_to_core_bpf::id()
         );
-        let feature_index = get_builtin_migration_feature_index(&config::id());
-        assert!(matches!(
-            feature_index,
-            BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
-        ));
-        let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
-            feature_index
-        else {
-            panic!("expect migrating builtin")
-        };
-        assert_eq!(
-            get_migration_feature_id(feature_index),
-            &feature_set::migrate_config_program_to_core_bpf::id()
-        );
         let feature_index = get_builtin_migration_feature_index(&address_lookup_table::id());
         assert!(matches!(
             feature_index,

+ 0 - 1
builtins/Cargo.toml

@@ -17,7 +17,6 @@ agave-feature-set = { workspace = true }
 solana-address-lookup-table-program = { workspace = true }
 solana-bpf-loader-program = { workspace = true }
 solana-compute-budget-program = { workspace = true }
-solana-config-program = { workspace = true }
 solana-loader-v4-program = { workspace = true }
 solana-program-runtime = { workspace = true }
 solana-pubkey = { workspace = true }

+ 7 - 25
builtins/src/lib.rs

@@ -77,19 +77,6 @@ pub static BUILTINS: &[BuiltinPrototype] = &[
         program_id: solana_stake_program::id(),
         entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
     },
-    BuiltinPrototype {
-        core_bpf_migration_config: Some(CoreBpfMigrationConfig {
-            source_buffer_address: buffer_accounts::config_program::id(),
-            upgrade_authority_address: None,
-            feature_id: agave_feature_set::migrate_config_program_to_core_bpf::id(),
-            migration_target: CoreBpfMigrationTargetType::Builtin,
-            datapoint_name: "migrate_builtin_to_core_bpf_config_program",
-        }),
-        name: "config_program",
-        enable_feature_id: None,
-        program_id: solana_config_program::id(),
-        entrypoint: solana_config_program::config_processor::Entrypoint::vm,
-    },
     testable_prototype!(BuiltinPrototype {
         core_bpf_migration_config: None,
         name: solana_bpf_loader_deprecated_program,
@@ -161,9 +148,6 @@ mod buffer_accounts {
     pub mod address_lookup_table_program {
         solana_pubkey::declare_id!("AhXWrD9BBUYcKjtpA3zuiiZG4ysbo6C6wjHo1QhERk6A");
     }
-    pub mod config_program {
-        solana_pubkey::declare_id!("BuafH9fBv62u6XjzrzS4ZjAE8963ejqF5rt1f8Uga4Q3");
-    }
     pub mod stake_program {
         solana_pubkey::declare_id!("8t3vv6v99tQA6Gp7fVdsBH66hQMaswH5qsJVqJqo8xvG");
     }
@@ -368,36 +352,34 @@ mod tests {
         );
         // Stake has a live migration config, so it has no test-only configs
         // to test here.
-        // Config has a live migration config, so it has no test-only configs
-        // to test here.
         assert_eq!(
-            &super::BUILTINS[4].core_bpf_migration_config,
+            &super::BUILTINS[3].core_bpf_migration_config,
             &Some(super::test_only::solana_bpf_loader_deprecated_program::CONFIG)
         );
         assert_eq!(
-            &super::BUILTINS[5].core_bpf_migration_config,
+            &super::BUILTINS[4].core_bpf_migration_config,
             &Some(super::test_only::solana_bpf_loader_program::CONFIG)
         );
         assert_eq!(
-            &super::BUILTINS[6].core_bpf_migration_config,
+            &super::BUILTINS[5].core_bpf_migration_config,
             &Some(super::test_only::solana_bpf_loader_upgradeable_program::CONFIG)
         );
         assert_eq!(
-            &super::BUILTINS[7].core_bpf_migration_config,
+            &super::BUILTINS[6].core_bpf_migration_config,
             &Some(super::test_only::compute_budget_program::CONFIG)
         );
         // Address Lookup Table has a live migration config, so it has no
         // test-only configs to test here.
         assert_eq!(
-            &super::BUILTINS[9].core_bpf_migration_config,
+            &super::BUILTINS[8].core_bpf_migration_config,
             &Some(super::test_only::zk_token_proof_program::CONFIG)
         );
         assert_eq!(
-            &super::BUILTINS[10].core_bpf_migration_config,
+            &super::BUILTINS[9].core_bpf_migration_config,
             &Some(super::test_only::loader_v4::CONFIG)
         );
         assert_eq!(
-            &super::BUILTINS[11].core_bpf_migration_config,
+            &super::BUILTINS[10].core_bpf_migration_config,
             &Some(super::test_only::zk_elgamal_proof_program::CONFIG)
         );
     }

+ 1 - 1
cli/Cargo.toml

@@ -42,7 +42,7 @@ solana-cluster-type = "=2.2.1"
 solana-commitment-config = "=2.2.1"
 solana-compute-budget = { workspace = true }
 solana-compute-budget-interface = { version = "=2.2.1", features = ["borsh"] }
-solana-config-program = { workspace = true }
+solana-config-program-client = { workspace = true, features = ["serde"] }
 solana-connection-cache = { workspace = true }
 solana-decode-error = "=2.2.1"
 solana-epoch-schedule = "=2.2.1"

+ 11 - 7
cli/src/validator_info.rs

@@ -20,7 +20,11 @@ use {
         keypair::DefaultSigner,
     },
     solana_cli_output::{CliValidatorInfo, CliValidatorInfoVec},
-    solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState},
+    solana_config_program_client::{
+        get_config_data,
+        instructions_bincode::{self as config_instruction, ConfigState},
+        ConfigKeys,
+    },
     solana_keypair::Keypair,
     solana_message::Message,
     solana_pubkey::Pubkey,
@@ -129,7 +133,7 @@ fn parse_validator_info(
     pubkey: &Pubkey,
     account: &Account,
 ) -> Result<(Pubkey, Map<String, serde_json::value::Value>), Box<dyn error::Error>> {
-    if account.owner != solana_config_program::id() {
+    if account.owner != solana_config_program_client::ID {
         return Err(format!("{pubkey} is not a validator info account").into());
     }
     let key_list: ConfigKeys = deserialize(&account.data)?;
@@ -302,7 +306,7 @@ pub fn process_set_validator_info(
     }
 
     // Check for existing validator-info account
-    let all_config = rpc_client.get_program_accounts(&solana_config_program::id())?;
+    let all_config = rpc_client.get_program_accounts(&solana_config_program_client::ID)?;
     let existing_account = all_config
         .iter()
         .filter(
@@ -334,7 +338,7 @@ pub fn process_set_validator_info(
         (config.signers[0].pubkey(), true),
     ];
     let data_len = ValidatorInfo::max_space()
-        .checked_add(ConfigKeys::serialized_size(keys.clone()))
+        .checked_add(serialized_size(&ConfigKeys { keys: keys.clone() }).unwrap())
         .expect("ValidatorInfo and two keys fit into a u64");
     let lamports = rpc_client.get_minimum_balance_for_rent_exemption(data_len as usize)?;
 
@@ -429,7 +433,7 @@ pub fn process_get_validator_info(
             rpc_client.get_account(&validator_info_pubkey)?,
         )]
     } else {
-        let all_config = rpc_client.get_program_accounts(&solana_config_program::id())?;
+        let all_config = rpc_client.get_program_accounts(&solana_config_program_client::ID)?;
         all_config
             .into_iter()
             .filter(|(_, validator_info_account)| {
@@ -583,7 +587,7 @@ mod tests {
             parse_validator_info(
                 &Pubkey::default(),
                 &Account {
-                    owner: solana_config_program::id(),
+                    owner: solana_config_program_client::ID,
                     data,
                     ..Account::default()
                 }
@@ -618,7 +622,7 @@ mod tests {
         assert!(parse_validator_info(
             &Pubkey::default(),
             &Account {
-                owner: solana_config_program::id(),
+                owner: solana_config_program_client::ID,
                 data,
                 ..Account::default()
             },

+ 0 - 4
compute-budget-instruction/src/builtin_programs_filter.rs

@@ -115,10 +115,6 @@ mod test {
                 solana_sdk_ids::stake::id(),
                 feature_set::migrate_stake_program_to_core_bpf::id(),
             ),
-            (
-                solana_sdk_ids::config::id(),
-                feature_set::migrate_config_program_to_core_bpf::id(),
-            ),
             (
                 solana_sdk_ids::address_lookup_table::id(),
                 feature_set::migrate_address_lookup_table_program_to_core_bpf::id(),

+ 1 - 1
install/Cargo.toml

@@ -30,7 +30,7 @@ serde_derive = { workspace = true }
 serde_yaml = { workspace = true }
 serde_yaml_08 = { package = "serde_yaml", version = "0.8.26" }
 solana-clap-utils = { workspace = true }
-solana-config-program = { workspace = true }
+solana-config-program-client = { workspace = true, features = ["serde"] }
 solana-hash = "=2.2.1"
 solana-keypair = "=2.2.1"
 solana-logger = "=2.3.1"

+ 4 - 1
install/src/command.rs

@@ -9,7 +9,10 @@ use {
     crossbeam_channel::unbounded,
     indicatif::{ProgressBar, ProgressStyle},
     serde_derive::{Deserialize, Serialize},
-    solana_config_program::{config_instruction, get_config_data, ConfigState},
+    solana_config_program_client::{
+        get_config_data,
+        instructions_bincode::{self as config_instruction, ConfigState},
+    },
     solana_hash::Hash,
     solana_keypair::{read_keypair_file, signable::Signable, Keypair},
     solana_message::Message,

+ 1 - 1
install/src/update_manifest.rs

@@ -1,6 +1,6 @@
 use {
     serde_derive::{Deserialize, Serialize},
-    solana_config_program::ConfigState,
+    solana_config_program_client::instructions_bincode::ConfigState,
     solana_hash::Hash,
     solana_keypair::signable::Signable,
     solana_pubkey::Pubkey,

+ 0 - 1
local-cluster/Cargo.toml

@@ -17,7 +17,6 @@ rand = { workspace = true }
 rayon = { workspace = true }
 solana-accounts-db = { workspace = true }
 solana-client = { workspace = true }
-solana-config-program = { workspace = true }
 solana-core = { workspace = true }
 solana-entry = { workspace = true }
 solana-gossip = { workspace = true }

+ 0 - 1
local-cluster/tests/local_cluster.rs

@@ -435,7 +435,6 @@ fn test_mainnet_beta_cluster_type() {
 
     // Programs that are available at epoch 0
     for program_id in [
-        &solana_config_program::id(),
         &solana_sdk::system_program::id(),
         &solana_sdk::stake::program::id(),
         &solana_vote_program::id(),

+ 1 - 1
program-test/src/programs.rs

@@ -56,7 +56,7 @@ static CORE_BPF_PROGRAMS: &[(Pubkey, Option<Pubkey>, &[u8])] = &[
     ),
     (
         solana_sdk_ids::config::ID,
-        Some(feature_set::migrate_config_program_to_core_bpf::ID),
+        None,
         include_bytes!("programs/core_bpf_config-3.0.0.so"),
     ),
     (

+ 0 - 40
programs/config/Cargo.toml

@@ -1,40 +0,0 @@
-[package]
-name = "solana-config-program"
-description = "Solana Config program"
-documentation = "https://docs.rs/solana-config-program"
-version = { workspace = true }
-authors = { workspace = true }
-repository = { workspace = true }
-homepage = { workspace = true }
-license = { workspace = true }
-edition = { workspace = true }
-
-[dependencies]
-bincode = { workspace = true }
-chrono = { workspace = true, features = ["default", "serde"] }
-serde = { workspace = true }
-serde_derive = { workspace = true }
-solana-account = { workspace = true }
-solana-bincode = { workspace = true }
-solana-instruction = { workspace = true }
-solana-log-collector = { workspace = true }
-solana-packet = { workspace = true }
-solana-program-runtime = { workspace = true }
-solana-pubkey = { workspace = true }
-solana-sdk-ids = { workspace = true }
-solana-short-vec = { workspace = true }
-solana-stake-interface = { workspace = true }
-solana-system-interface = { workspace = true }
-solana-transaction-context = { workspace = true }
-
-[dev-dependencies]
-solana-keypair = { workspace = true }
-solana-logger = { workspace = true }
-solana-signer = { workspace = true }
-
-[lib]
-crate-type = ["lib"]
-name = "solana_config_program"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]

+ 0 - 49
programs/config/src/config_instruction.rs

@@ -1,49 +0,0 @@
-use {
-    crate::{id, ConfigKeys, ConfigState},
-    solana_instruction::{AccountMeta, Instruction},
-    solana_pubkey::Pubkey,
-    solana_system_interface::instruction as system_instruction,
-};
-
-fn initialize_account<T: ConfigState>(config_pubkey: &Pubkey) -> Instruction {
-    let account_metas = vec![AccountMeta::new(*config_pubkey, true)];
-    let account_data = (ConfigKeys { keys: vec![] }, T::default());
-    Instruction::new_with_bincode(id(), &account_data, account_metas)
-}
-
-/// Create a new, empty configuration account
-pub fn create_account<T: ConfigState>(
-    from_account_pubkey: &Pubkey,
-    config_account_pubkey: &Pubkey,
-    lamports: u64,
-    keys: Vec<(Pubkey, bool)>,
-) -> Vec<Instruction> {
-    let space = T::max_space() + ConfigKeys::serialized_size(keys);
-    vec![
-        system_instruction::create_account(
-            from_account_pubkey,
-            config_account_pubkey,
-            lamports,
-            space,
-            &id(),
-        ),
-        initialize_account::<T>(config_account_pubkey),
-    ]
-}
-
-/// Store new data in a configuration account
-pub fn store<T: ConfigState>(
-    config_account_pubkey: &Pubkey,
-    is_config_signer: bool,
-    keys: Vec<(Pubkey, bool)>,
-    data: &T,
-) -> Instruction {
-    let mut account_metas = vec![AccountMeta::new(*config_account_pubkey, is_config_signer)];
-    for (signer_pubkey, _) in keys.iter().filter(|(_, is_signer)| *is_signer) {
-        if signer_pubkey != config_account_pubkey {
-            account_metas.push(AccountMeta::new(*signer_pubkey, true));
-        }
-    }
-    let account_data = (ConfigKeys { keys }, data);
-    Instruction::new_with_bincode(id(), &account_data, account_metas)
-}

+ 0 - 848
programs/config/src/config_processor.rs

@@ -1,848 +0,0 @@
-//! Config program
-
-use {
-    crate::ConfigKeys, bincode::deserialize, solana_bincode::limited_deserialize,
-    solana_instruction::error::InstructionError, solana_log_collector::ic_msg,
-    solana_program_runtime::declare_process_instruction, solana_pubkey::Pubkey,
-    solana_transaction_context::IndexOfAccount, std::collections::BTreeSet,
-};
-
-pub const DEFAULT_COMPUTE_UNITS: u64 = 450;
-
-declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
-    let transaction_context = &invoke_context.transaction_context;
-    let instruction_context = transaction_context.get_current_instruction_context()?;
-    let data = instruction_context.get_instruction_data();
-
-    let key_list: ConfigKeys = limited_deserialize(data, solana_packet::PACKET_DATA_SIZE as u64)?;
-    let config_account_key = transaction_context.get_key_of_account_at_index(
-        instruction_context.get_index_of_instruction_account_in_transaction(0)?,
-    )?;
-    let config_account =
-        instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
-    let is_config_account_signer = config_account.is_signer();
-    let current_data: ConfigKeys = {
-        if config_account.get_owner() != &crate::id() {
-            return Err(InstructionError::InvalidAccountOwner);
-        }
-
-        deserialize(config_account.get_data()).map_err(|err| {
-            ic_msg!(
-                invoke_context,
-                "Unable to deserialize config account: {}",
-                err
-            );
-            InstructionError::InvalidAccountData
-        })?
-    };
-    drop(config_account);
-
-    let current_signer_keys: Vec<Pubkey> = current_data
-        .keys
-        .iter()
-        .filter(|(_, is_signer)| *is_signer)
-        .map(|(pubkey, _)| *pubkey)
-        .collect();
-    if current_signer_keys.is_empty() {
-        // Config account keypair must be a signer on account initialization,
-        // or when no signers specified in Config data
-        if !is_config_account_signer {
-            return Err(InstructionError::MissingRequiredSignature);
-        }
-    }
-
-    let mut counter = 0;
-    for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
-        counter += 1;
-        if signer != config_account_key {
-            let signer_account = instruction_context
-                .try_borrow_instruction_account(transaction_context, counter as IndexOfAccount)
-                .map_err(|_| {
-                    ic_msg!(
-                        invoke_context,
-                        "account {:?} is not in account list",
-                        signer,
-                    );
-                    InstructionError::MissingRequiredSignature
-                })?;
-            if !signer_account.is_signer() {
-                ic_msg!(
-                    invoke_context,
-                    "account {:?} signer_key().is_none()",
-                    signer
-                );
-                return Err(InstructionError::MissingRequiredSignature);
-            }
-            if signer_account.get_key() != signer {
-                ic_msg!(
-                    invoke_context,
-                    "account[{:?}].signer_key() does not match Config data)",
-                    counter + 1
-                );
-                return Err(InstructionError::MissingRequiredSignature);
-            }
-            // If Config account is already initialized, update signatures must match Config data
-            if !current_data.keys.is_empty()
-                && !current_signer_keys.iter().any(|pubkey| pubkey == signer)
-            {
-                ic_msg!(
-                    invoke_context,
-                    "account {:?} is not in stored signer list",
-                    signer
-                );
-                return Err(InstructionError::MissingRequiredSignature);
-            }
-        } else if !is_config_account_signer {
-            ic_msg!(invoke_context, "account[0].signer_key().is_none()");
-            return Err(InstructionError::MissingRequiredSignature);
-        }
-    }
-
-    // dedupe signers
-    let total_new_keys = key_list.keys.len();
-    let unique_new_keys = key_list.keys.into_iter().collect::<BTreeSet<_>>();
-    if unique_new_keys.len() != total_new_keys {
-        ic_msg!(invoke_context, "new config contains duplicate keys");
-        return Err(InstructionError::InvalidArgument);
-    }
-
-    // Check for Config data signers not present in incoming account update
-    if current_signer_keys.len() > counter {
-        ic_msg!(
-            invoke_context,
-            "too few signers: {:?}; expected: {:?}",
-            counter,
-            current_signer_keys.len()
-        );
-        return Err(InstructionError::MissingRequiredSignature);
-    }
-
-    let mut config_account =
-        instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
-    if config_account.get_data().len() < data.len() {
-        ic_msg!(invoke_context, "instruction data too large");
-        return Err(InstructionError::InvalidInstructionData);
-    }
-    config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
-    Ok(())
-});
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::{config_instruction, get_config_data, id, ConfigKeys, ConfigState},
-        bincode::serialized_size,
-        serde_derive::{Deserialize, Serialize},
-        solana_account::{AccountSharedData, ReadableAccount},
-        solana_instruction::AccountMeta,
-        solana_keypair::Keypair,
-        solana_program_runtime::invoke_context::mock_process_instruction,
-        solana_pubkey::Pubkey,
-        solana_signer::Signer,
-        solana_system_interface::instruction::SystemInstruction,
-    };
-
-    fn process_instruction(
-        instruction_data: &[u8],
-        transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
-        instruction_accounts: Vec<AccountMeta>,
-        expected_result: Result<(), InstructionError>,
-    ) -> Vec<AccountSharedData> {
-        mock_process_instruction(
-            &id(),
-            Vec::new(),
-            instruction_data,
-            transaction_accounts,
-            instruction_accounts,
-            expected_result,
-            Entrypoint::vm,
-            |_invoke_context| {},
-            |_invoke_context| {},
-        )
-    }
-
-    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
-    struct MyConfig {
-        pub item: u64,
-    }
-    impl Default for MyConfig {
-        fn default() -> Self {
-            Self { item: 123_456_789 }
-        }
-    }
-    impl MyConfig {
-        pub fn new(item: u64) -> Self {
-            Self { item }
-        }
-        pub fn deserialize(input: &[u8]) -> Option<Self> {
-            deserialize(input).ok()
-        }
-    }
-
-    impl ConfigState for MyConfig {
-        fn max_space() -> u64 {
-            serialized_size(&Self::default()).unwrap()
-        }
-    }
-
-    fn create_config_account(keys: Vec<(Pubkey, bool)>) -> (Keypair, AccountSharedData) {
-        let from_pubkey = Pubkey::new_unique();
-        let config_keypair = Keypair::new();
-        let config_pubkey = config_keypair.pubkey();
-        let instructions =
-            config_instruction::create_account::<MyConfig>(&from_pubkey, &config_pubkey, 1, keys);
-        let system_instruction = limited_deserialize(
-            &instructions[0].data,
-            solana_packet::PACKET_DATA_SIZE as u64,
-        )
-        .unwrap();
-        let SystemInstruction::CreateAccount {
-            lamports: _,
-            space,
-            owner: _,
-        } = system_instruction
-        else {
-            panic!("Not a CreateAccount system instruction")
-        };
-        let config_account = AccountSharedData::new(0, space as usize, &id());
-        let accounts = process_instruction(
-            &instructions[1].data,
-            vec![(config_pubkey, config_account)],
-            vec![AccountMeta {
-                pubkey: config_pubkey,
-                is_signer: true,
-                is_writable: true,
-            }],
-            Ok(()),
-        );
-        (config_keypair, accounts[0].clone())
-    }
-
-    #[test]
-    fn test_process_create_ok() {
-        solana_logger::setup();
-        let (_, config_account) = create_config_account(vec![]);
-        assert_eq!(
-            Some(MyConfig::default()),
-            deserialize(get_config_data(config_account.data()).unwrap()).ok()
-        );
-    }
-
-    #[test]
-    fn test_process_store_ok() {
-        solana_logger::setup();
-        let keys = vec![];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![(config_pubkey, config_account)],
-            vec![AccountMeta {
-                pubkey: config_pubkey,
-                is_signer: true,
-                is_writable: true,
-            }],
-            Ok(()),
-        );
-        assert_eq!(
-            Some(my_config),
-            deserialize(get_config_data(accounts[0].data()).unwrap()).ok()
-        );
-    }
-
-    #[test]
-    fn test_process_store_fail_instruction_data_too_large() {
-        solana_logger::setup();
-        let keys = vec![];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        let mut instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        instruction.data = vec![0; 123]; // <-- Replace data with a vector that's too large
-        process_instruction(
-            &instruction.data,
-            vec![(config_pubkey, config_account)],
-            vec![AccountMeta {
-                pubkey: config_pubkey,
-                is_signer: true,
-                is_writable: true,
-            }],
-            Err(InstructionError::InvalidInstructionData),
-        );
-    }
-
-    #[test]
-    fn test_process_store_fail_account0_not_signer() {
-        solana_logger::setup();
-        let keys = vec![];
-        let (config_keypair, config_account) = create_config_account(keys);
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        let mut instruction = config_instruction::store(&config_pubkey, true, vec![], &my_config);
-        instruction.accounts[0].is_signer = false; // <----- not a signer
-        process_instruction(
-            &instruction.data,
-            vec![(config_pubkey, config_account)],
-            vec![AccountMeta {
-                pubkey: config_pubkey,
-                is_signer: false,
-                is_writable: true,
-            }],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-    }
-
-    #[test]
-    fn test_process_store_with_additional_signers() {
-        solana_logger::setup();
-        let pubkey = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer1_pubkey = Pubkey::new_unique();
-        let keys = vec![
-            (pubkey, false),
-            (signer0_pubkey, true),
-            (signer1_pubkey, true),
-        ];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account),
-                (signer1_pubkey, signer1_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-        let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
-        assert_eq!(meta_data.keys, keys);
-        assert_eq!(
-            Some(my_config),
-            deserialize(get_config_data(accounts[0].data()).unwrap()).ok()
-        );
-    }
-
-    #[test]
-    fn test_process_store_without_config_signer() {
-        solana_logger::setup();
-        let pubkey = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let keys = vec![(pubkey, false), (signer0_pubkey, true)];
-        let (config_keypair, _) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-        let signer0_account = AccountSharedData::new(0, 0, &id());
-
-        let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![(signer0_pubkey, signer0_account)],
-            vec![AccountMeta {
-                pubkey: signer0_pubkey,
-                is_signer: true,
-                is_writable: false,
-            }],
-            Err(InstructionError::InvalidAccountData),
-        );
-    }
-
-    #[test]
-    fn test_process_store_with_bad_additional_signer() {
-        solana_logger::setup();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer1_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let keys = vec![(signer0_pubkey, true)];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        // Config-data pubkey doesn't match signer
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account.clone()),
-                (signer1_pubkey, signer1_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-
-        // Config-data pubkey not a signer
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: false,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-    }
-
-    #[test]
-    fn test_config_updates() {
-        solana_logger::setup();
-        let pubkey = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer1_pubkey = Pubkey::new_unique();
-        let signer2_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let signer2_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let keys = vec![
-            (pubkey, false),
-            (signer0_pubkey, true),
-            (signer1_pubkey, true),
-        ];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account.clone()),
-                (signer1_pubkey, signer1_account.clone()),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-
-        // Update with expected signatures
-        let new_config = MyConfig::new(84);
-        let instruction =
-            config_instruction::store(&config_pubkey, false, keys.clone(), &new_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, accounts[0].clone()),
-                (signer0_pubkey, signer0_account.clone()),
-                (signer1_pubkey, signer1_account.clone()),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: false,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-        let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
-        assert_eq!(meta_data.keys, keys);
-        assert_eq!(
-            new_config,
-            MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap()
-        );
-
-        // Attempt update with incomplete signatures
-        let keys = vec![(pubkey, false), (signer0_pubkey, true)];
-        let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, accounts[0].clone()),
-                (signer0_pubkey, signer0_account.clone()),
-                (signer1_pubkey, signer1_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: false,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: false,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-
-        // Attempt update with incorrect signatures
-        let keys = vec![
-            (pubkey, false),
-            (signer0_pubkey, true),
-            (signer2_pubkey, true),
-        ];
-        let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, accounts[0].clone()),
-                (signer0_pubkey, signer0_account),
-                (signer2_pubkey, signer2_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: false,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer2_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-    }
-
-    #[test]
-    fn test_config_initialize_contains_duplicates_fails() {
-        solana_logger::setup();
-        let config_address = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let keys = vec![
-            (config_address, false),
-            (signer0_pubkey, true),
-            (signer0_pubkey, true),
-        ];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        // Attempt initialization with duplicate signer inputs
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::InvalidArgument),
-        );
-    }
-
-    #[test]
-    fn test_config_update_contains_duplicates_fails() {
-        solana_logger::setup();
-        let config_address = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer1_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let keys = vec![
-            (config_address, false),
-            (signer0_pubkey, true),
-            (signer1_pubkey, true),
-        ];
-        let (config_keypair, config_account) = create_config_account(keys.clone());
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account.clone()),
-                (signer1_pubkey, signer1_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer1_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-
-        // Attempt update with duplicate signer inputs
-        let new_config = MyConfig::new(84);
-        let dupe_keys = vec![
-            (config_address, false),
-            (signer0_pubkey, true),
-            (signer0_pubkey, true),
-        ];
-        let instruction = config_instruction::store(&config_pubkey, false, dupe_keys, &new_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, accounts[0].clone()),
-                (signer0_pubkey, signer0_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::InvalidArgument),
-        );
-    }
-
-    #[test]
-    fn test_config_updates_requiring_config() {
-        solana_logger::setup();
-        let pubkey = Pubkey::new_unique();
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let keys = vec![
-            (pubkey, false),
-            (signer0_pubkey, true),
-            (signer0_pubkey, true),
-        ]; // Dummy keys for account sizing
-        let (config_keypair, config_account) = create_config_account(keys);
-        let config_pubkey = config_keypair.pubkey();
-        let my_config = MyConfig::new(42);
-        let keys = vec![
-            (pubkey, false),
-            (signer0_pubkey, true),
-            (config_keypair.pubkey(), true),
-        ];
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account.clone()),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-
-        // Update with expected signatures
-        let new_config = MyConfig::new(84);
-        let instruction =
-            config_instruction::store(&config_pubkey, true, keys.clone(), &new_config);
-        let accounts = process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, accounts[0].clone()),
-                (signer0_pubkey, signer0_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Ok(()),
-        );
-        let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
-        assert_eq!(meta_data.keys, keys);
-        assert_eq!(
-            new_config,
-            MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap()
-        );
-
-        // Attempt update with incomplete signatures
-        let keys = vec![(pubkey, false), (config_keypair.pubkey(), true)];
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
-        process_instruction(
-            &instruction.data,
-            vec![(config_pubkey, accounts[0].clone())],
-            vec![AccountMeta {
-                pubkey: config_pubkey,
-                is_signer: true,
-                is_writable: true,
-            }],
-            Err(InstructionError::MissingRequiredSignature),
-        );
-    }
-
-    #[test]
-    fn test_config_initialize_no_panic() {
-        let from_pubkey = Pubkey::new_unique();
-        let config_pubkey = Pubkey::new_unique();
-        let (_, _config_account) = create_config_account(vec![]);
-        let instructions =
-            config_instruction::create_account::<MyConfig>(&from_pubkey, &config_pubkey, 1, vec![]);
-        process_instruction(
-            &instructions[1].data,
-            Vec::new(),
-            Vec::new(),
-            Err(InstructionError::NotEnoughAccountKeys),
-        );
-    }
-
-    #[test]
-    fn test_config_bad_owner() {
-        let from_pubkey = Pubkey::new_unique();
-        let config_pubkey = Pubkey::new_unique();
-        let new_config = MyConfig::new(84);
-        let signer0_pubkey = Pubkey::new_unique();
-        let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let config_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
-        let (_, _config_account) = create_config_account(vec![]);
-        let keys = vec![
-            (from_pubkey, false),
-            (signer0_pubkey, true),
-            (config_pubkey, true),
-        ];
-
-        let instruction = config_instruction::store(&config_pubkey, true, keys, &new_config);
-        process_instruction(
-            &instruction.data,
-            vec![
-                (config_pubkey, config_account),
-                (signer0_pubkey, signer0_account),
-            ],
-            vec![
-                AccountMeta {
-                    pubkey: config_pubkey,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: signer0_pubkey,
-                    is_signer: true,
-                    is_writable: false,
-                },
-            ],
-            Err(InstructionError::InvalidAccountOwner),
-        );
-    }
-}

+ 0 - 59
programs/config/src/date_instruction.rs

@@ -1,59 +0,0 @@
-///
-/// A library for creating a trusted date oracle.
-///
-use bincode::{deserialize, serialized_size};
-use {
-    crate::{config_instruction, ConfigState},
-    chrono::{
-        prelude::{DateTime, TimeZone, Utc},
-        serde::ts_seconds,
-    },
-    serde_derive::{Deserialize, Serialize},
-    solana_instruction::Instruction,
-    solana_pubkey::Pubkey,
-};
-
-#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
-pub struct DateConfig {
-    #[serde(with = "ts_seconds")]
-    pub date_time: DateTime<Utc>,
-}
-
-impl Default for DateConfig {
-    fn default() -> Self {
-        Self {
-            date_time: Utc.timestamp_opt(0, 0).unwrap(),
-        }
-    }
-}
-impl DateConfig {
-    pub fn new(date_time: DateTime<Utc>) -> Self {
-        Self { date_time }
-    }
-
-    pub fn deserialize(input: &[u8]) -> Option<Self> {
-        deserialize(input).ok()
-    }
-}
-
-impl ConfigState for DateConfig {
-    fn max_space() -> u64 {
-        serialized_size(&Self::default()).unwrap()
-    }
-}
-
-/// Create a date account. The date is set to the Unix epoch.
-pub fn create_account(
-    payer_pubkey: &Pubkey,
-    date_pubkey: &Pubkey,
-    lamports: u64,
-) -> Vec<Instruction> {
-    config_instruction::create_account::<DateConfig>(payer_pubkey, date_pubkey, lamports, vec![])
-}
-
-/// Set the date in the date account. The account pubkey must be signed in the
-/// transaction containing this instruction.
-pub fn store(date_pubkey: &Pubkey, date_time: DateTime<Utc>) -> Instruction {
-    let date_config = DateConfig::new(date_time);
-    config_instruction::store(date_pubkey, true, vec![], &date_config)
-}

+ 0 - 69
programs/config/src/lib.rs

@@ -1,69 +0,0 @@
-#![allow(clippy::arithmetic_side_effects)]
-pub mod config_instruction;
-pub mod config_processor;
-#[deprecated(
-    since = "2.0.0",
-    note = "The config program API no longer supports date instructions."
-)]
-pub mod date_instruction;
-
-pub use solana_sdk_ids::config::id;
-#[allow(deprecated)]
-use solana_stake_interface::config::Config as StakeConfig;
-use {
-    bincode::{deserialize, serialize, serialized_size},
-    serde_derive::{Deserialize, Serialize},
-    solana_account::{Account, AccountSharedData},
-    solana_pubkey::Pubkey,
-    solana_short_vec as short_vec,
-};
-
-pub trait ConfigState: serde::Serialize + Default {
-    /// Maximum space that the serialized representation will require
-    fn max_space() -> u64;
-}
-
-// TODO move ConfigState into `solana_program` to implement trait locally
-#[allow(deprecated)]
-impl ConfigState for StakeConfig {
-    fn max_space() -> u64 {
-        serialized_size(&StakeConfig::default()).unwrap()
-    }
-}
-
-/// A collection of keys to be stored in Config account data.
-#[derive(Debug, Default, Deserialize, Serialize)]
-pub struct ConfigKeys {
-    // Each key tuple comprises a unique `Pubkey` identifier,
-    // and `bool` whether that key is a signer of the data
-    #[serde(with = "short_vec")]
-    pub keys: Vec<(Pubkey, bool)>,
-}
-
-impl ConfigKeys {
-    pub fn serialized_size(keys: Vec<(Pubkey, bool)>) -> u64 {
-        serialized_size(&ConfigKeys { keys }).unwrap()
-    }
-}
-
-pub fn get_config_data(bytes: &[u8]) -> Result<&[u8], bincode::Error> {
-    deserialize::<ConfigKeys>(bytes)
-        .and_then(|keys| serialized_size(&keys))
-        .map(|offset| &bytes[offset as usize..])
-}
-
-// utility for pre-made Accounts
-pub fn create_config_account<T: ConfigState>(
-    keys: Vec<(Pubkey, bool)>,
-    config_data: &T,
-    lamports: u64,
-) -> AccountSharedData {
-    let mut data = serialize(&ConfigKeys { keys }).unwrap();
-    data.extend_from_slice(&serialize(config_data).unwrap());
-    AccountSharedData::from(Account {
-        lamports,
-        data,
-        owner: id(),
-        ..Account::default()
-    })
-}

+ 19 - 21
programs/sbf/Cargo.lock

@@ -3005,6 +3005,16 @@ dependencies = [
  "unicase",
 ]
 
+[[package]]
+name = "kaigan"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ba15de5aeb137f0f65aa3bf82187647f1285abfe5b20c80c2c37f7007ad519a"
+dependencies = [
+ "borsh 0.10.3",
+ "serde",
+]
+
 [[package]]
 name = "keccak"
 version = "0.1.5"
@@ -5263,7 +5273,7 @@ dependencies = [
  "solana-account",
  "solana-account-decoder-client-types",
  "solana-clock",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-epoch-schedule",
  "solana-fee-calculator",
  "solana-instruction",
@@ -5613,7 +5623,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-loader-v4-program",
  "solana-program-runtime",
  "solana-pubkey",
@@ -5636,7 +5645,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-loader-v4-program",
  "solana-pubkey",
  "solana-sdk-ids",
@@ -5874,25 +5882,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "solana-config-program"
-version = "2.3.0"
+name = "solana-config-program-client"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53aceac36f105fd4922e29b4f0c1f785b69d7b3e7e387e384b8985c8e0c3595e"
 dependencies = [
  "bincode",
- "chrono",
+ "borsh 0.10.3",
+ "kaigan",
  "serde",
- "serde_derive",
- "solana-account",
- "solana-bincode",
- "solana-instruction",
- "solana-log-collector",
- "solana-packet",
- "solana-program-runtime",
- "solana-pubkey",
- "solana-sdk-ids",
- "solana-short-vec",
- "solana-stake-interface",
- "solana-system-interface",
- "solana-transaction-context 2.3.0",
+ "solana-program",
 ]
 
 [[package]]
@@ -7610,7 +7609,6 @@ dependencies = [
  "solana-builtins",
  "solana-compute-budget",
  "solana-compute-budget-instruction",
- "solana-config-program",
  "solana-cost-model",
  "solana-fee",
  "solana-inline-spl",
@@ -8528,7 +8526,7 @@ dependencies = [
  "solana-account",
  "solana-bincode",
  "solana-clock",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-genesis-config",
  "solana-instruction",
  "solana-log-collector",

+ 1 - 1
programs/stake/Cargo.toml

@@ -16,7 +16,7 @@ log = { workspace = true }
 solana-account = { workspace = true }
 solana-bincode = { workspace = true }
 solana-clock = { workspace = true }
-solana-config-program = { workspace = true }
+solana-config-program-client = { workspace = true, features = ["serde"] }
 solana-genesis-config = { workspace = true }
 solana-instruction = { workspace = true }
 solana-log-collector = { workspace = true }

+ 20 - 3
programs/stake/src/config.rs

@@ -6,13 +6,30 @@
 )]
 pub use solana_stake_interface::config::*;
 use {
-    bincode::deserialize,
-    solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
-    solana_config_program::{create_config_account, get_config_data},
+    bincode::{deserialize, serialize},
+    solana_account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
+    solana_config_program_client::{get_config_data, ConfigKeys},
     solana_genesis_config::GenesisConfig,
+    solana_pubkey::Pubkey,
     solana_transaction_context::BorrowedAccount,
 };
 
+#[allow(deprecated)]
+fn create_config_account(
+    keys: Vec<(Pubkey, bool)>,
+    config_data: &Config,
+    lamports: u64,
+) -> AccountSharedData {
+    let mut data = serialize(&ConfigKeys { keys }).unwrap();
+    data.extend_from_slice(&serialize(config_data).unwrap());
+    AccountSharedData::from(Account {
+        lamports,
+        data,
+        owner: solana_sdk_ids::config::id(),
+        ..Account::default()
+    })
+}
+
 #[allow(deprecated)]
 pub fn from(account: &BorrowedAccount) -> Option<Config> {
     get_config_data(account.get_data())

+ 0 - 1
runtime/Cargo.toml

@@ -55,7 +55,6 @@ solana-bucket-map = { workspace = true }
 solana-builtins = { workspace = true }
 solana-compute-budget = { workspace = true }
 solana-compute-budget-instruction = { workspace = true }
-solana-config-program = { workspace = true }
 solana-cost-model = { workspace = true }
 solana-fee = { workspace = true }
 solana-frozen-abi = { workspace = true, optional = true, features = [

+ 3 - 4
runtime/src/bank/builtin_programs.rs

@@ -155,10 +155,9 @@ mod tests_core_bpf_migration {
     #[test_case(TestPrototype::Builtin(&BUILTINS[0]); "system")]
     #[test_case(TestPrototype::Builtin(&BUILTINS[1]); "vote")]
     #[test_case(TestPrototype::Builtin(&BUILTINS[2]); "stake")]
-    #[test_case(TestPrototype::Builtin(&BUILTINS[3]); "config")]
-    #[test_case(TestPrototype::Builtin(&BUILTINS[4]); "bpf_loader_deprecated")]
-    #[test_case(TestPrototype::Builtin(&BUILTINS[5]); "bpf_loader")]
-    #[test_case(TestPrototype::Builtin(&BUILTINS[8]); "address_lookup_table")]
+    #[test_case(TestPrototype::Builtin(&BUILTINS[3]); "bpf_loader_deprecated")]
+    #[test_case(TestPrototype::Builtin(&BUILTINS[4]); "bpf_loader")]
+    #[test_case(TestPrototype::Builtin(&BUILTINS[7]); "address_lookup_table")]
     fn test_core_bpf_migration(prototype: TestPrototype) {
         let (mut genesis_config, mint_keypair) =
             create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);

+ 0 - 1
runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs

@@ -110,7 +110,6 @@ mod tests {
     #[test_case(solana_sdk::bpf_loader_deprecated::id(), None)]
     #[test_case(solana_sdk::bpf_loader_upgradeable::id(), None)]
     #[test_case(solana_sdk::compute_budget::id(), None)]
-    #[test_case(solana_config_program::id(), None)]
     #[test_case(solana_stake_program::id(), None)]
     #[test_case(solana_system_program::id(), None)]
     #[test_case(solana_vote_program::id(), None)]

+ 5 - 5
runtime/src/bank/tests.rs

@@ -6515,26 +6515,26 @@ fn test_bank_hash_consistency() {
         if bank.slot == 0 {
             assert_eq!(
                 bank.hash().to_string(),
-                "Hn2FoJuoFWXVFVnwcQ6peuT24mUPmhDtXHXVjKD7M4yP",
+                "5nHFM2YArJdULMoAEtn2cXSaqk4v1UXs9upTvoc2FMn7",
             );
         }
 
         if bank.slot == 32 {
             assert_eq!(
                 bank.hash().to_string(),
-                "Hdrk5wqzRZbofSgZMC3ztfNimrFu6DeYp751JWvtabo"
+                "FPr64zXMcEE45qWRYy7hpvNRpzZD2ckqHes13uyiU1to"
             );
         }
         if bank.slot == 64 {
             assert_eq!(
                 bank.hash().to_string(),
-                "4EcAFkTxymwwPGeCgadhkrkg2hqfAPzuQZoN2NFqPzyg"
+                "HENrhATjg2gghYyV34CLPnMUq2VuTKwUjGXWwAz96Vzs"
             );
         }
         if bank.slot == 128 {
             assert_eq!(
                 bank.hash().to_string(),
-                "4BK3VANr5mhyRyrwbUHYb2kmM5m76PBGkhmKMrQ2aq7L"
+                "GjpfTe9dmB1HbrnC4BMaETPAqPUtXvXNG5ccnHSeMPnH"
             );
             break;
         }
@@ -6753,7 +6753,7 @@ fn test_shrink_candidate_slots_cached() {
     // No more slots should be shrunk
     assert_eq!(bank2.shrink_candidate_slots(), 0);
     // alive_counts represents the count of alive accounts in the three slots 0,1,2
-    assert_eq!(alive_counts, vec![15, 1, 6]);
+    assert_eq!(alive_counts, vec![14, 1, 6]);
 }
 
 #[test]

+ 1 - 1
runtime/src/genesis_utils.rs

@@ -29,7 +29,7 @@ pub fn bootstrap_validator_stake_lamports() -> u64 {
 
 // Number of lamports automatically used for genesis accounts
 pub const fn genesis_sysvar_and_builtin_program_lamports() -> u64 {
-    const NUM_BUILTIN_PROGRAMS: u64 = 9;
+    const NUM_BUILTIN_PROGRAMS: u64 = 8;
     const NUM_PRECOMPILES: u64 = 2;
     const STAKE_HISTORY_MIN_BALANCE: u64 = 114_979_200;
     const CLOCK_SYSVAR_MIN_BALANCE: u64 = 1_169_280;

+ 0 - 2
scripts/patch-crates.sh

@@ -43,7 +43,6 @@ update_solana_dependencies() {
     solana-address-lookup-table-program
     solana-bpf-loader-program
     solana-compute-budget-program
-    solana-config-program
     solana-stake-program
     solana-system-program
     solana-vote-program
@@ -134,7 +133,6 @@ patch_crates_io_solana_no_header() {
   crates_map+=("solana-address-lookup-table-program programs/address-lookup-table")
   crates_map+=("solana-bpf-loader-program programs/bpf_loader")
   crates_map+=("solana-compute-budget-program programs/compute-budget")
-  crates_map+=("solana-config-program programs/config")
   crates_map+=("solana-stake-program programs/stake")
   crates_map+=("solana-system-program programs/system")
   crates_map+=("solana-vote-program programs/vote")

+ 19 - 21
svm/examples/Cargo.lock

@@ -2935,6 +2935,16 @@ dependencies = [
  "unicase",
 ]
 
+[[package]]
+name = "kaigan"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ba15de5aeb137f0f65aa3bf82187647f1285abfe5b20c80c2c37f7007ad519a"
+dependencies = [
+ "borsh 0.10.4",
+ "serde",
+]
+
 [[package]]
 name = "keccak"
 version = "0.1.5"
@@ -5121,7 +5131,7 @@ dependencies = [
  "solana-account",
  "solana-account-decoder-client-types",
  "solana-clock",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-epoch-schedule",
  "solana-fee-calculator",
  "solana-instruction",
@@ -5471,7 +5481,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-loader-v4-program",
  "solana-program-runtime",
  "solana-pubkey",
@@ -5494,7 +5503,6 @@ dependencies = [
  "solana-address-lookup-table-program",
  "solana-bpf-loader-program",
  "solana-compute-budget-program",
- "solana-config-program",
  "solana-loader-v4-program",
  "solana-pubkey",
  "solana-sdk-ids",
@@ -5732,25 +5740,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "solana-config-program"
-version = "2.3.0"
+name = "solana-config-program-client"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53aceac36f105fd4922e29b4f0c1f785b69d7b3e7e387e384b8985c8e0c3595e"
 dependencies = [
  "bincode",
- "chrono",
+ "borsh 0.10.4",
+ "kaigan",
  "serde",
- "serde_derive",
- "solana-account",
- "solana-bincode",
- "solana-instruction",
- "solana-log-collector",
- "solana-packet",
- "solana-program-runtime",
- "solana-pubkey",
- "solana-sdk-ids",
- "solana-short-vec",
- "solana-stake-interface",
- "solana-system-interface",
- "solana-transaction-context 2.3.0",
+ "solana-program",
 ]
 
 [[package]]
@@ -7434,7 +7433,6 @@ dependencies = [
  "solana-builtins",
  "solana-compute-budget",
  "solana-compute-budget-instruction",
- "solana-config-program",
  "solana-cost-model",
  "solana-fee",
  "solana-inline-spl",
@@ -7849,7 +7847,7 @@ dependencies = [
  "solana-account",
  "solana-bincode",
  "solana-clock",
- "solana-config-program",
+ "solana-config-program-client",
  "solana-genesis-config",
  "solana-instruction",
  "solana-log-collector",

+ 6 - 6
test-validator/src/lib.rs

@@ -1303,8 +1303,8 @@ mod test {
     async fn test_core_bpf_programs() {
         let (test_validator, _payer) = TestValidatorGenesis::default()
             .deactivate_features(&[
-                // Don't migrate the config program.
-                solana_sdk::feature_set::migrate_config_program_to_core_bpf::id(),
+                // Don't migrate the lookup table program.
+                solana_sdk::feature_set::migrate_address_lookup_table_program_to_core_bpf::id(),
             ])
             .start_async()
             .await;
@@ -1320,14 +1320,14 @@ mod test {
             .await
             .unwrap();
 
-        // Address lookup table is a BPF program.
+        // Address lookup table is builtin.
         let account = fetched_programs[0].as_ref().unwrap();
-        assert_eq!(account.owner, solana_sdk_ids::bpf_loader_upgradeable::id());
+        assert_eq!(account.owner, solana_sdk_ids::native_loader::id());
         assert!(account.executable);
 
-        // Config is a builtin.
+        // Config is a a BPF program.
         let account = fetched_programs[1].as_ref().unwrap();
-        assert_eq!(account.owner, solana_sdk_ids::native_loader::id());
+        assert_eq!(account.owner, solana_sdk_ids::bpf_loader_upgradeable::id());
         assert!(account.executable);
 
         // Feature Gate is a BPF program.