Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/litesvm/src/features.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use solana_address::Address;

/// Feature gates currently activated on Solana mainnet-beta, paired with their
/// activation slot, sourced from the cluster on 2026-10-15.
/// activation slot, sourced from the cluster on 2026-10-26.
pub const MAINNET_ACTIVE_FEATURES: &[(Address, u64)] = &[
(agave_feature_set::deprecate_rewards_sysvar::ID, 55728001),
(agave_feature_set::pico_inflation::ID, 57456000),
Expand Down Expand Up @@ -636,6 +636,7 @@ pub const MAINNET_ACTIVE_FEATURES: &[(Address, u64)] = &[
agave_feature_set::formalize_loaded_transaction_data_size::ID,
381888000,
),
(agave_feature_set::alpenglow::ID, 459648000),
(
agave_feature_set::disable_zk_elgamal_proof_program::ID,
347760000,
Expand Down
76 changes: 34 additions & 42 deletions crates/litesvm/tests/feature_accounts.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,54 @@
use {
agave_feature_set::{accounts_lt_hash, alpenglow, raise_cpi_nesting_limit_to_8},
litesvm::{features::MAINNET_ACTIVE_FEATURES, LiteSVM},
solana_feature_gate_interface::{self as feature_gate, Feature},
};

#[test_log::test]
fn new_initializes_accounts_for_enabled_features() {
let svm = LiteSVM::new();
let feature_id = accounts_lt_hash::id();
for (feature_id, activation_slot) in MAINNET_ACTIVE_FEATURES {
let account = svm
.get_account(feature_id)
.unwrap_or_else(|| panic!("active feature account {feature_id} should exist"));
let feature =
feature_gate::from_account(&account).expect("feature account should deserialize");

let account = svm
.get_account(&feature_id)
.expect("active feature account should exist");
let feature = feature_gate::from_account(&account).expect("feature account should deserialize");

let expected_slot = MAINNET_ACTIVE_FEATURES
.iter()
.find(|(id, _)| *id == feature_id)
.map(|(_, slot)| *slot)
.expect("accounts_lt_hash should be in the active feature list");

assert_eq!(account.owner, solana_sdk_ids::feature::id());
assert_eq!(
feature,
Feature {
activated_at: Some(expected_slot)
}
);
assert!(
account.lamports >= svm.minimum_balance_for_rent_exemption(Feature::size_of()),
"feature account should be rent exempt"
);
assert_eq!(account.owner, solana_sdk_ids::feature::id(), "{feature_id}");
assert_eq!(
feature,
Feature {
activated_at: Some(*activation_slot)
},
"{feature_id}"
);
assert!(
account.lamports >= svm.minimum_balance_for_rent_exemption(Feature::size_of()),
"feature account {feature_id} should be rent exempt"
);
}
}

#[test_log::test]
fn new_does_not_initialize_accounts_for_inactive_mainnet_features() {
let svm = LiteSVM::new();
assert!(
svm.get_account(&raise_cpi_nesting_limit_to_8::id())
.is_none(),
"feature accounts should not be created for features inactive on mainnet"
);
for feature_id in LiteSVM::mainnet_feature_set().inactive() {
assert!(
svm.get_account(feature_id).is_none(),
"inactive feature account {feature_id} should not exist"
);
}
}

#[test_log::test]
fn mainnet_feature_set_matches_mainnet_activation_state() {
fn mainnet_feature_set_matches_mainnet_snapshot() {
let feature_set = LiteSVM::mainnet_feature_set();

assert!(
feature_set.is_active(&accounts_lt_hash::id()),
"accounts_lt_hash is active on mainnet (SIMD-0215)"
);
assert!(
!feature_set.is_active(&alpenglow::id()),
"alpenglow is not yet active on mainnet"
);
assert!(
!feature_set.is_active(&raise_cpi_nesting_limit_to_8::id()),
"raise_cpi_nesting_limit_to_8 is not yet active on mainnet"
);
assert_eq!(feature_set.active().len(), MAINNET_ACTIVE_FEATURES.len());
for (feature_id, activation_slot) in MAINNET_ACTIVE_FEATURES {
assert_eq!(
feature_set.active().get(feature_id),
Some(activation_slot),
"{feature_id}"
);
}
}
Loading