solana/core/tests/storage_stage.rs

262 lines
8.7 KiB
Rust

// Long-running storage_stage tests
#[cfg(test)]
mod tests {
use log::*;
use solana_core::{
commitment::BlockCommitmentCache,
storage_stage::{
get_identity_index_from_signature, test_cluster_info, StorageStage, StorageState,
SLOTS_PER_TURN_TEST,
},
};
use solana_ledger::{
bank_forks::BankForks,
blockstore::Blockstore,
blockstore_processor, create_new_tmp_ledger, entry,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
};
use solana_runtime::bank::Bank;
use solana_sdk::{
clock::DEFAULT_TICKS_PER_SLOT,
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
transaction::Transaction,
};
use solana_storage_program::storage_instruction::{self, StorageAccountType};
use std::{
fs::remove_dir_all,
sync::{
atomic::{AtomicBool, Ordering},
mpsc::channel,
Arc, RwLock,
},
thread::sleep,
time::Duration,
};
fn get_mining_result(storage_state: &StorageState, key: &Signature) -> Hash {
let idx = get_identity_index_from_signature(key);
storage_state.state.read().unwrap().storage_results[idx]
}
#[test]
fn test_storage_stage_process_account_proofs() {
solana_logger::setup();
let keypair = Arc::new(Keypair::new());
let storage_keypair = Arc::new(Keypair::new());
let archiver_keypair = Arc::new(Keypair::new());
let exit = Arc::new(AtomicBool::new(false));
let GenesisConfigInfo {
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(1000);
genesis_config
.native_instruction_processors
.push(solana_storage_program::solana_storage_program!());
let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);
let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
let bank = Bank::new(&genesis_config);
let bank = Arc::new(bank);
let bank_forks = Arc::new(RwLock::new(BankForks::new_from_banks(&[bank.clone()], 0)));
let block_commitment_cache = Arc::new(RwLock::new(
BlockCommitmentCache::default_with_blockstore(blockstore.clone()),
));
let cluster_info = test_cluster_info(&keypair.pubkey());
let (bank_sender, bank_receiver) = channel();
let storage_state = StorageState::new(
&bank.last_blockhash(),
SLOTS_PER_TURN_TEST,
bank.slots_per_segment(),
);
let storage_stage = StorageStage::new(
&storage_state,
bank_receiver,
Some(blockstore.clone()),
&keypair,
&storage_keypair,
&exit.clone(),
&bank_forks,
&cluster_info,
block_commitment_cache,
);
bank_sender.send(vec![bank.clone()]).unwrap();
// create accounts
let bank = Arc::new(Bank::new_from_parent(&bank, &keypair.pubkey(), 1));
let account_ixs = storage_instruction::create_storage_account(
&mint_keypair.pubkey(),
&Pubkey::new_rand(),
&archiver_keypair.pubkey(),
1,
StorageAccountType::Archiver,
);
let account_tx = Transaction::new_signed_instructions(
&[&mint_keypair, &archiver_keypair],
&account_ixs,
bank.last_blockhash(),
);
bank.process_transaction(&account_tx).expect("create");
bank_sender.send(vec![bank.clone()]).unwrap();
let mut reference_keys;
{
let keys = &storage_state.state.read().unwrap().storage_keys;
reference_keys = vec![0; keys.len()];
reference_keys.copy_from_slice(keys);
}
let keypair = Keypair::new();
let mining_proof_ix = storage_instruction::mining_proof(
&archiver_keypair.pubkey(),
Hash::default(),
0,
keypair.sign_message(b"test"),
bank.last_blockhash(),
);
let next_bank = Arc::new(Bank::new_from_parent(&bank, &keypair.pubkey(), 2));
//register ticks so the program reports a different segment
blockstore_processor::process_entries(
&next_bank,
&entry::create_ticks(
DEFAULT_TICKS_PER_SLOT * next_bank.slots_per_segment() + 1,
0,
bank.last_blockhash(),
),
true,
None,
)
.unwrap();
let message = Message::new_with_payer(&[mining_proof_ix], Some(&mint_keypair.pubkey()));
let mining_proof_tx = Transaction::new(
&[&mint_keypair, archiver_keypair.as_ref()],
message,
next_bank.last_blockhash(),
);
next_bank
.process_transaction(&mining_proof_tx)
.expect("process txs");
bank_sender.send(vec![next_bank]).unwrap();
for _ in 0..5 {
{
let keys = &storage_state.state.read().unwrap().storage_keys;
if keys[..] != *reference_keys.as_slice() {
break;
}
}
sleep(Duration::new(1, 0));
}
debug!("joining..?");
exit.store(true, Ordering::Relaxed);
storage_stage.join().unwrap();
{
let keys = &storage_state.state.read().unwrap().storage_keys;
assert_ne!(keys[..], *reference_keys);
}
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_storage_stage_process_banks() {
solana_logger::setup();
let keypair = Arc::new(Keypair::new());
let storage_keypair = Arc::new(Keypair::new());
let exit = Arc::new(AtomicBool::new(false));
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(1000);
let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);
let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
let slot = 1;
let bank = Arc::new(Bank::new(&genesis_config));
let bank_forks = Arc::new(RwLock::new(BankForks::new_from_banks(&[bank.clone()], 0)));
let block_commitment_cache = Arc::new(RwLock::new(
BlockCommitmentCache::default_with_blockstore(blockstore.clone()),
));
let cluster_info = test_cluster_info(&keypair.pubkey());
let (bank_sender, bank_receiver) = channel();
let storage_state = StorageState::new(
&bank.last_blockhash(),
SLOTS_PER_TURN_TEST,
bank.slots_per_segment(),
);
let storage_stage = StorageStage::new(
&storage_state,
bank_receiver,
Some(blockstore.clone()),
&keypair,
&storage_keypair,
&exit.clone(),
&bank_forks,
&cluster_info,
block_commitment_cache,
);
bank_sender.send(vec![bank.clone()]).unwrap();
let keypair = Keypair::new();
let hash = Hash::default();
let signature = keypair.sign_message(&hash.as_ref());
let mut result = get_mining_result(&storage_state, &signature);
assert_eq!(result, Hash::default());
let mut last_bank = bank;
let rooted_banks = (slot..slot + last_bank.slots_per_segment() + 1)
.map(|i| {
let bank = Arc::new(Bank::new_from_parent(&last_bank, &keypair.pubkey(), i));
blockstore_processor::process_entries(
&bank,
&entry::create_ticks(64, 0, bank.last_blockhash()),
true,
None,
)
.expect("failed process entries");
last_bank = bank;
last_bank.clone()
})
.collect::<Vec<_>>();
bank_sender.send(rooted_banks).unwrap();
if solana_perf::perf_libs::api().is_some() {
for _ in 0..5 {
result = get_mining_result(&storage_state, &signature);
if result != Hash::default() {
info!("found result = {:?} sleeping..", result);
break;
}
info!("result = {:?} sleeping..", result);
sleep(Duration::new(1, 0));
}
}
info!("joining..?");
exit.store(true, Ordering::Relaxed);
storage_stage.join().unwrap();
if solana_perf::perf_libs::api().is_some() {
assert_ne!(result, Hash::default());
} else {
assert_eq!(result, Hash::default());
}
remove_dir_all(ledger_path).unwrap();
}
}