Skip to content

Commit 191cf4c

Browse files
authored
test validator: make feature accounts additive (solana-labs#3766)
* test validator: make feature accounts additive * add test for feature override
1 parent 6117b48 commit 191cf4c

File tree

2 files changed

+132
-17
lines changed

2 files changed

+132
-17
lines changed

runtime/src/genesis_utils.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ pub fn activate_feature(genesis_config: &mut GenesisConfig, feature_id: Pubkey)
231231
}
232232

233233
#[allow(clippy::too_many_arguments)]
234-
pub fn create_genesis_config_with_leader_ex(
234+
pub fn create_genesis_config_with_leader_ex_no_features(
235235
mint_lamports: u64,
236236
mint_pubkey: &Pubkey,
237237
validator_pubkey: &Pubkey,
@@ -295,6 +295,38 @@ pub fn create_genesis_config_with_leader_ex(
295295
};
296296

297297
solana_stake_program::add_genesis_accounts(&mut genesis_config);
298+
299+
genesis_config
300+
}
301+
302+
#[allow(clippy::too_many_arguments)]
303+
pub fn create_genesis_config_with_leader_ex(
304+
mint_lamports: u64,
305+
mint_pubkey: &Pubkey,
306+
validator_pubkey: &Pubkey,
307+
validator_vote_account_pubkey: &Pubkey,
308+
validator_stake_account_pubkey: &Pubkey,
309+
validator_stake_lamports: u64,
310+
validator_lamports: u64,
311+
fee_rate_governor: FeeRateGovernor,
312+
rent: Rent,
313+
cluster_type: ClusterType,
314+
initial_accounts: Vec<(Pubkey, AccountSharedData)>,
315+
) -> GenesisConfig {
316+
let mut genesis_config = create_genesis_config_with_leader_ex_no_features(
317+
mint_lamports,
318+
mint_pubkey,
319+
validator_pubkey,
320+
validator_vote_account_pubkey,
321+
validator_stake_account_pubkey,
322+
validator_stake_lamports,
323+
validator_lamports,
324+
fee_rate_governor,
325+
rent,
326+
cluster_type,
327+
initial_accounts,
328+
);
329+
298330
if genesis_config.cluster_type == ClusterType::Development {
299331
activate_all_features(&mut genesis_config);
300332
}

test-validator/src/lib.rs

Lines changed: 99 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ use {
3434
solana_rpc_client::{nonblocking, rpc_client::RpcClient},
3535
solana_rpc_client_api::request::MAX_MULTIPLE_ACCOUNTS,
3636
solana_runtime::{
37-
bank_forks::BankForks, genesis_utils::create_genesis_config_with_leader_ex,
38-
runtime_config::RuntimeConfig, snapshot_config::SnapshotConfig,
37+
bank_forks::BankForks,
38+
genesis_utils::{self, create_genesis_config_with_leader_ex_no_features},
39+
runtime_config::RuntimeConfig,
40+
snapshot_config::SnapshotConfig,
3941
},
4042
solana_sdk::{
4143
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
@@ -44,6 +46,7 @@ use {
4446
commitment_config::CommitmentConfig,
4547
epoch_schedule::EpochSchedule,
4648
exit::Exit,
49+
feature_set::FeatureSet,
4750
fee_calculator::FeeRateGovernor,
4851
instruction::{AccountMeta, Instruction},
4952
message::Message,
@@ -829,7 +832,7 @@ impl TestValidator {
829832
);
830833
}
831834

832-
let mut genesis_config = create_genesis_config_with_leader_ex(
835+
let mut genesis_config = create_genesis_config_with_leader_ex_no_features(
833836
mint_lamports,
834837
&mint_address,
835838
&validator_identity.pubkey(),
@@ -852,23 +855,21 @@ impl TestValidator {
852855
genesis_config.ticks_per_slot = ticks_per_slot;
853856
}
854857

855-
// Remove features tagged to deactivate
856-
for deactivate_feature_pk in &config.deactivate_feature_set {
857-
if FEATURE_NAMES.contains_key(deactivate_feature_pk) {
858-
match genesis_config.accounts.remove(deactivate_feature_pk) {
859-
Some(_) => info!("Feature for {:?} deactivated", deactivate_feature_pk),
860-
None => warn!(
861-
"Feature {:?} set for deactivation not found in genesis_config account list, ignored.",
862-
deactivate_feature_pk
863-
),
864-
}
858+
// Only activate features which are not explicitly deactivated.
859+
let mut feature_set = FeatureSet::default().inactive;
860+
for feature in &config.deactivate_feature_set {
861+
if feature_set.remove(feature) {
862+
info!("Feature for {:?} deactivated", feature)
865863
} else {
866864
warn!(
867865
"Feature {:?} set for deactivation is not a known Feature public key",
868-
deactivate_feature_pk
869-
);
866+
feature,
867+
)
870868
}
871869
}
870+
for feature in feature_set {
871+
genesis_utils::activate_feature(&mut genesis_config, feature);
872+
}
872873

873874
let ledger_path = match &config.ledger_path {
874875
None => create_new_tmp_ledger!(&genesis_config).0,
@@ -1193,7 +1194,7 @@ impl Drop for TestValidator {
11931194

11941195
#[cfg(test)]
11951196
mod test {
1196-
use super::*;
1197+
use {super::*, solana_sdk::feature::Feature};
11971198

11981199
#[test]
11991200
fn get_health() {
@@ -1217,4 +1218,86 @@ mod test {
12171218
// `start()` blows up when run within tokio
12181219
let (_test_validator, _payer) = TestValidatorGenesis::default().start();
12191220
}
1221+
1222+
#[tokio::test]
1223+
async fn test_deactivate_features() {
1224+
let mut control = FeatureSet::default().inactive;
1225+
let mut deactivate_features = Vec::new();
1226+
[
1227+
solana_sdk::feature_set::deprecate_rewards_sysvar::id(),
1228+
solana_sdk::feature_set::disable_fees_sysvar::id(),
1229+
]
1230+
.into_iter()
1231+
.for_each(|feature| {
1232+
control.remove(&feature);
1233+
deactivate_features.push(feature);
1234+
});
1235+
1236+
// Convert to `Vec` so we can get a slice.
1237+
let control: Vec<Pubkey> = control.into_iter().collect();
1238+
1239+
let (test_validator, _payer) = TestValidatorGenesis::default()
1240+
.deactivate_features(&deactivate_features)
1241+
.start_async()
1242+
.await;
1243+
1244+
let rpc_client = test_validator.get_async_rpc_client();
1245+
1246+
// Our deactivated features should be inactive.
1247+
let inactive_feature_accounts = rpc_client
1248+
.get_multiple_accounts(&deactivate_features)
1249+
.await
1250+
.unwrap();
1251+
for f in inactive_feature_accounts {
1252+
assert!(f.is_none());
1253+
}
1254+
1255+
// Everything else should be active.
1256+
for chunk in control.chunks(100) {
1257+
let active_feature_accounts = rpc_client.get_multiple_accounts(chunk).await.unwrap();
1258+
for f in active_feature_accounts {
1259+
let account = f.unwrap(); // Should be `Some`.
1260+
let feature_state: Feature = bincode::deserialize(account.data()).unwrap();
1261+
assert!(feature_state.activated_at.is_some());
1262+
}
1263+
}
1264+
}
1265+
1266+
#[tokio::test]
1267+
async fn test_override_feature_account() {
1268+
let with_deactivate_flag = solana_sdk::feature_set::deprecate_rewards_sysvar::id();
1269+
let without_deactivate_flag = solana_sdk::feature_set::disable_fees_sysvar::id();
1270+
1271+
let owner = Pubkey::new_unique();
1272+
let account = || AccountSharedData::new(100_000, 0, &owner);
1273+
1274+
let (test_validator, _payer) = TestValidatorGenesis::default()
1275+
.deactivate_features(&[with_deactivate_flag]) // Just deactivate one feature.
1276+
.add_accounts([
1277+
(with_deactivate_flag, account()), // But add both accounts.
1278+
(without_deactivate_flag, account()),
1279+
])
1280+
.start_async()
1281+
.await;
1282+
1283+
let rpc_client = test_validator.get_async_rpc_client();
1284+
1285+
let our_accounts = rpc_client
1286+
.get_multiple_accounts(&[with_deactivate_flag, without_deactivate_flag])
1287+
.await
1288+
.unwrap();
1289+
1290+
// The first one, where we provided `--deactivate-feature`, should be
1291+
// the account we provided.
1292+
let overriden_account = our_accounts[0].as_ref().unwrap();
1293+
assert_eq!(overriden_account.lamports, 100_000);
1294+
assert_eq!(overriden_account.data.len(), 0);
1295+
assert_eq!(overriden_account.owner, owner);
1296+
1297+
// The second one should be a feature account.
1298+
let feature_account = our_accounts[1].as_ref().unwrap();
1299+
assert_eq!(feature_account.owner, solana_sdk::feature::id());
1300+
let feature_state: Feature = bincode::deserialize(feature_account.data()).unwrap();
1301+
assert!(feature_state.activated_at.is_some());
1302+
}
12201303
}

0 commit comments

Comments
 (0)