Storage fixes

* replicators generate their sample values
* fixes to replicator block height logic
This commit is contained in:
Stephen Akridge 2019-01-02 11:02:15 -08:00 committed by sakridge
parent c0c38463c7
commit 1fd7bd7ede
13 changed files with 302 additions and 135 deletions

View File

@ -29,6 +29,7 @@ fn entrypoint(
StorageProgram::SubmitMiningProof { StorageProgram::SubmitMiningProof {
sha_state, sha_state,
entry_height, entry_height,
..
} => { } => {
info!( info!(
"Mining proof submitted with state {:?} entry_height: {}", "Mining proof submitted with state {:?} entry_height: {}",

View File

@ -27,6 +27,7 @@ fn main() {
.long("network") .long("network")
.value_name("HOST:PORT") .value_name("HOST:PORT")
.takes_value(true) .takes_value(true)
.required(true)
.help("Rendezvous with the network at this gossip entry point"), .help("Rendezvous with the network at this gossip entry point"),
) )
.arg( .arg(

View File

@ -1,11 +1,15 @@
use crate::hash::Hash; use crate::hash::Hash;
use crate::pubkey::Pubkey; use crate::pubkey::Pubkey;
use crate::signature::{Keypair, KeypairUtil}; use crate::signature::{Keypair, KeypairUtil, Signature};
use crate::transaction::Transaction; use crate::transaction::Transaction;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub enum StorageProgram { pub enum StorageProgram {
SubmitMiningProof { sha_state: Hash, entry_height: u64 }, SubmitMiningProof {
sha_state: Hash,
entry_height: u64,
signature: Signature,
},
} }
pub const STORAGE_PROGRAM_ID: [u8; 32] = [ pub const STORAGE_PROGRAM_ID: [u8; 32] = [
@ -27,6 +31,7 @@ pub trait StorageTransaction {
sha_state: Hash, sha_state: Hash,
last_id: Hash, last_id: Hash,
entry_height: u64, entry_height: u64,
signature: Signature,
) -> Self; ) -> Self;
} }
@ -36,10 +41,12 @@ impl StorageTransaction for Transaction {
sha_state: Hash, sha_state: Hash,
last_id: Hash, last_id: Hash,
entry_height: u64, entry_height: u64,
signature: Signature,
) -> Self { ) -> Self {
let program = StorageProgram::SubmitMiningProof { let program = StorageProgram::SubmitMiningProof {
sha_state, sha_state,
entry_height, entry_height,
signature,
}; };
Transaction::new( Transaction::new(
from_keypair, from_keypair,

View File

@ -38,13 +38,15 @@ pub fn chacha_cbc_encrypt_ledger(
slice: u64, slice: u64,
out_path: &Path, out_path: &Path,
ivec: &mut [u8; CHACHA_BLOCK_SIZE], ivec: &mut [u8; CHACHA_BLOCK_SIZE],
) -> io::Result<()> { ) -> io::Result<usize> {
let mut out_file = let mut out_file =
BufWriter::new(File::create(out_path).expect("Can't open ledger encrypted data file")); BufWriter::new(File::create(out_path).expect("Can't open ledger encrypted data file"));
let mut buffer = [0; 8 * 1024]; const BUFFER_SIZE: usize = 8 * 1024;
let mut encrypted_buffer = [0; 8 * 1024]; let mut buffer = [0; BUFFER_SIZE];
let mut encrypted_buffer = [0; BUFFER_SIZE];
let key = [0; CHACHA_KEY_SIZE]; let key = [0; CHACHA_KEY_SIZE];
let mut total_entries = 0; let mut total_entries = 0;
let mut total_size = 0;
let mut entry = slice; let mut entry = slice;
loop { loop {
@ -60,10 +62,18 @@ pub fn chacha_cbc_encrypt_ledger(
slice, num_entries, entry_len slice, num_entries, entry_len
); );
debug!("read {} bytes", entry_len); debug!("read {} bytes", entry_len);
let size = entry_len as usize; let mut size = entry_len as usize;
if size == 0 { if size == 0 {
break; break;
} }
if size < BUFFER_SIZE {
// We are on the last block, round to the nearest key_size
// boundary
size = (size + CHACHA_KEY_SIZE - 1) & !(CHACHA_KEY_SIZE - 1);
}
total_size += size;
chacha_cbc_encrypt(&buffer[..size], &mut encrypted_buffer[..size], &key, ivec); chacha_cbc_encrypt(&buffer[..size], &mut encrypted_buffer[..size], &key, ivec);
if let Err(res) = out_file.write(&encrypted_buffer[..size]) { if let Err(res) = out_file.write(&encrypted_buffer[..size]) {
println!("Error writing file! {:?}", res); println!("Error writing file! {:?}", res);
@ -79,7 +89,7 @@ pub fn chacha_cbc_encrypt_ledger(
} }
} }
} }
Ok(()) Ok(total_size)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -10,6 +10,7 @@ use crate::leader_scheduler::LeaderScheduler;
use crate::rpc::JsonRpcService; use crate::rpc::JsonRpcService;
use crate::rpc_pubsub::PubSubService; use crate::rpc_pubsub::PubSubService;
use crate::service::Service; use crate::service::Service;
use crate::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use crate::tpu::{Tpu, TpuReturnType}; use crate::tpu::{Tpu, TpuReturnType};
use crate::tpu_forwarder::TpuForwarder; use crate::tpu_forwarder::TpuForwarder;
use crate::tvu::{Sockets, Tvu, TvuReturnType}; use crate::tvu::{Sockets, Tvu, TvuReturnType};
@ -118,6 +119,34 @@ impl Fullnode {
sigverify_disabled: bool, sigverify_disabled: bool,
leader_scheduler: LeaderScheduler, leader_scheduler: LeaderScheduler,
rpc_port: Option<u16>, rpc_port: Option<u16>,
) -> Self {
// TODO: remove this, temporary parameter to configure
// storage amount differently for test configurations
// so tests don't take forever to run.
const NUM_HASHES_FOR_STORAGE_ROTATE: u64 = 1024;
Self::new_with_storage_rotate(
node,
ledger_path,
keypair,
vote_signer,
leader_addr,
sigverify_disabled,
leader_scheduler,
rpc_port,
NUM_HASHES_FOR_STORAGE_ROTATE,
)
}
pub fn new_with_storage_rotate(
node: Node,
ledger_path: &str,
keypair: Arc<Keypair>,
vote_signer: Arc<VoteSignerProxy>,
leader_addr: Option<SocketAddr>,
sigverify_disabled: bool,
leader_scheduler: LeaderScheduler,
rpc_port: Option<u16>,
storage_rotate_count: u64,
) -> Self { ) -> Self {
let leader_scheduler = Arc::new(RwLock::new(leader_scheduler)); let leader_scheduler = Arc::new(RwLock::new(leader_scheduler));
@ -152,6 +181,7 @@ impl Fullnode {
ledger_path, ledger_path,
sigverify_disabled, sigverify_disabled,
rpc_port, rpc_port,
storage_rotate_count,
); );
match leader_addr { match leader_addr {
@ -183,6 +213,7 @@ impl Fullnode {
ledger_path: &str, ledger_path: &str,
sigverify_disabled: bool, sigverify_disabled: bool,
rpc_port: Option<u16>, rpc_port: Option<u16>,
storage_rotate_count: u64,
) -> Self { ) -> Self {
let mut rpc_addr = node.info.rpc; let mut rpc_addr = node.info.rpc;
let mut rpc_pubsub_addr = node.info.rpc_pubsub; let mut rpc_pubsub_addr = node.info.rpc_pubsub;
@ -283,6 +314,7 @@ impl Fullnode {
&cluster_info, &cluster_info,
sockets, sockets,
db_ledger.clone(), db_ledger.clone(),
storage_rotate_count,
); );
let tpu_forwarder = TpuForwarder::new( let tpu_forwarder = TpuForwarder::new(
node.sockets node.sockets
@ -444,6 +476,7 @@ impl Fullnode {
&self.cluster_info, &self.cluster_info,
sockets, sockets,
self.db_ledger.clone(), self.db_ledger.clone(),
STORAGE_ROTATE_TEST_COUNT,
); );
let tpu_forwarder = TpuForwarder::new( let tpu_forwarder = TpuForwarder::new(
self.tpu_sockets self.tpu_sockets
@ -638,6 +671,7 @@ mod tests {
make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig, make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig,
}; };
use crate::service::Service; use crate::service::Service;
use crate::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use crate::streamer::responder; use crate::streamer::responder;
use crate::vote_signer_proxy::VoteSignerProxy; use crate::vote_signer_proxy::VoteSignerProxy;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
@ -679,6 +713,7 @@ mod tests {
&validator_ledger_path, &validator_ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
v.close().unwrap(); v.close().unwrap();
remove_dir_all(validator_ledger_path).unwrap(); remove_dir_all(validator_ledger_path).unwrap();
@ -722,6 +757,7 @@ mod tests {
&validator_ledger_path, &validator_ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
) )
}) })
.collect(); .collect();

View File

@ -9,15 +9,15 @@ use crate::leader_scheduler::LeaderScheduler;
use crate::result::Result; use crate::result::Result;
use crate::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler}; use crate::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
use crate::service::Service; use crate::service::Service;
use crate::storage_stage::ENTRIES_PER_SEGMENT; use crate::storage_stage::{get_segment_from_entry, ENTRIES_PER_SEGMENT};
use crate::streamer::BlobReceiver; use crate::streamer::BlobReceiver;
use crate::thin_client::retry_get_balance; use crate::thin_client::{retry_get_balance, ThinClient};
use crate::window_service::window_service; use crate::window_service::window_service;
use rand::thread_rng; use rand::thread_rng;
use rand::Rng; use rand::Rng;
use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT};
use solana_sdk::hash::{Hash, Hasher}; use solana_sdk::hash::{Hash, Hasher};
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::storage_program::StorageTransaction; use solana_sdk::storage_program::StorageTransaction;
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use std::fs::File; use std::fs::File;
@ -43,6 +43,7 @@ pub struct Replicator {
t_window: JoinHandle<()>, t_window: JoinHandle<()>,
pub retransmit_receiver: BlobReceiver, pub retransmit_receiver: BlobReceiver,
exit: Arc<AtomicBool>, exit: Arc<AtomicBool>,
entry_height: u64,
} }
pub fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> { pub fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> {
@ -80,6 +81,23 @@ pub fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> {
Ok(hasher.result()) Ok(hasher.result())
} }
fn get_entry_heights_from_last_id(
signature: &ring::signature::Signature,
storage_entry_height: u64,
) -> (u64, u64) {
let signature_vec = signature.as_ref();
let mut segment_index = u64::from(signature_vec[0])
| (u64::from(signature_vec[1]) << 8)
| (u64::from(signature_vec[1]) << 16)
| (u64::from(signature_vec[2]) << 24);
let max_segment_index = get_segment_from_entry(storage_entry_height);
segment_index %= max_segment_index as u64;
let entry_height = segment_index * ENTRIES_PER_SEGMENT;
let max_entry_height = entry_height + ENTRIES_PER_SEGMENT;
(entry_height, max_entry_height)
}
impl Replicator { impl Replicator {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub fn new( pub fn new(
@ -120,53 +138,18 @@ impl Replicator {
); );
info!("polling for leader"); info!("polling for leader");
let leader; let leader = Self::poll_for_leader(&cluster_info)?;
loop {
if let Some(l) = cluster_info.read().unwrap().get_gossip_top_leader() {
leader = l.clone();
break;
}
sleep(Duration::from_millis(900));
info!("{}", cluster_info.read().unwrap().node_info_trace());
}
info!("Got leader: {:?}", leader); info!("Got leader: {:?}", leader);
let mut storage_last_id; let (storage_last_id, storage_entry_height) =
let mut storage_entry_height; Self::poll_for_last_id_and_entry_height(&cluster_info)?;
loop {
let rpc_client = {
let cluster_info = cluster_info.read().unwrap();
let rpc_peers = cluster_info.rpc_peers();
info!("rpc peers: {:?}", rpc_peers);
let node_idx = thread_rng().gen_range(0, rpc_peers.len());
RpcClient::new_from_socket(rpc_peers[node_idx].rpc)
};
storage_last_id = rpc_client
.make_rpc_request(2, RpcRequest::GetStorageMiningLastId, None)
.expect("rpc request")
.to_string();
storage_entry_height = rpc_client
.make_rpc_request(2, RpcRequest::GetStorageMiningEntryHeight, None)
.expect("rpc request")
.as_u64()
.unwrap();
if storage_entry_height != 0 {
break;
}
}
let signature = keypair.sign(storage_last_id.as_ref()); let signature = keypair.sign(storage_last_id.as_ref());
let signature = signature.as_ref(); let (entry_height, max_entry_height) =
let block_index = u64::from(signature[0]) get_entry_heights_from_last_id(&signature, storage_entry_height);
| (u64::from(signature[1]) << 8)
| (u64::from(signature[1]) << 16) info!("replicating entry_height: {}", entry_height);
| (u64::from(signature[2]) << 24);
let mut entry_height = block_index * ENTRIES_PER_SEGMENT;
entry_height %= storage_entry_height;
let max_entry_height = entry_height + ENTRIES_PER_SEGMENT;
let repair_socket = Arc::new(node.sockets.repair); let repair_socket = Arc::new(node.sockets.repair);
let mut blob_sockets: Vec<Arc<UdpSocket>> = let mut blob_sockets: Vec<Arc<UdpSocket>> =
@ -208,7 +191,141 @@ impl Replicator {
let mut client = mk_client(&leader); let mut client = mk_client(&leader);
if retry_get_balance(&mut client, &keypair.pubkey(), None).is_none() { Self::get_airdrop_tokens(&mut client, keypair, &leader_info);
info!("Done downloading ledger at {}", ledger_path.unwrap());
let ledger_path = Path::new(ledger_path.unwrap());
let ledger_data_file_encrypted = ledger_path.join("ledger.enc");
let mut sampling_offsets = Vec::new();
#[cfg(not(feature = "chacha"))]
sampling_offsets.push(0);
#[cfg(feature = "chacha")]
{
use crate::storage_stage::NUM_STORAGE_SAMPLES;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaChaRng;
let mut ivec = [0u8; 64];
ivec.copy_from_slice(signature.as_ref());
let num_encrypted_bytes = chacha_cbc_encrypt_ledger(
&db_ledger,
entry_height,
&ledger_data_file_encrypted,
&mut ivec,
)?;
let num_chacha_blocks = num_encrypted_bytes / CHACHA_BLOCK_SIZE;
let mut rng_seed = [0u8; 32];
rng_seed.copy_from_slice(&signature.as_ref()[0..32]);
let mut rng = ChaChaRng::from_seed(rng_seed);
for _ in 0..NUM_STORAGE_SAMPLES {
sampling_offsets.push(rng.gen_range(0, num_chacha_blocks) as u64);
}
}
info!("Done encrypting the ledger");
match sample_file(&ledger_data_file_encrypted, &sampling_offsets) {
Ok(hash) => {
let last_id = client.get_last_id();
info!("sampled hash: {}", hash);
let mut tx = Transaction::storage_new_mining_proof(
&keypair,
hash,
last_id,
entry_height,
Signature::new(signature.as_ref()),
);
client
.retry_transfer(&keypair, &mut tx, 10)
.expect("transfer didn't work!");
}
Err(e) => info!("Error occurred while sampling: {:?}", e),
}
Ok(Self {
gossip_service,
fetch_stage,
t_window,
retransmit_receiver,
exit,
entry_height,
})
}
pub fn close(self) {
self.exit.store(true, Ordering::Relaxed);
self.join()
}
pub fn join(self) {
self.gossip_service.join().unwrap();
self.fetch_stage.join().unwrap();
self.t_window.join().unwrap();
// Drain the queue here to prevent self.retransmit_receiver from being dropped
// before the window_service thread is joined
let mut retransmit_queue_count = 0;
while let Ok(_blob) = self.retransmit_receiver.recv_timeout(Duration::new(1, 0)) {
retransmit_queue_count += 1;
}
debug!("retransmit channel count: {}", retransmit_queue_count);
}
pub fn entry_height(&self) -> u64 {
self.entry_height
}
fn poll_for_leader(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<NodeInfo> {
for _ in 0..30 {
if let Some(l) = cluster_info.read().unwrap().get_gossip_top_leader() {
return Ok(l.clone());
}
sleep(Duration::from_millis(900));
info!("{}", cluster_info.read().unwrap().node_info_trace());
}
Err(Error::new(ErrorKind::Other, "Couldn't find leader"))?
}
fn poll_for_last_id_and_entry_height(
cluster_info: &Arc<RwLock<ClusterInfo>>,
) -> Result<(String, u64)> {
for _ in 0..10 {
let rpc_client = {
let cluster_info = cluster_info.read().unwrap();
let rpc_peers = cluster_info.rpc_peers();
debug!("rpc peers: {:?}", rpc_peers);
let node_idx = thread_rng().gen_range(0, rpc_peers.len());
RpcClient::new_from_socket(rpc_peers[node_idx].rpc)
};
let storage_last_id = rpc_client
.make_rpc_request(2, RpcRequest::GetStorageMiningLastId, None)
.expect("rpc request")
.to_string();
let storage_entry_height = rpc_client
.make_rpc_request(2, RpcRequest::GetStorageMiningEntryHeight, None)
.expect("rpc request")
.as_u64()
.unwrap();
if get_segment_from_entry(storage_entry_height) != 0 {
return Ok((storage_last_id, storage_entry_height));
}
info!("max entry_height: {}", storage_entry_height);
sleep(Duration::from_secs(3));
}
Err(Error::new(
ErrorKind::Other,
"Couldn't get last_id or entry_height",
))?
}
fn get_airdrop_tokens(client: &mut ThinClient, keypair: &Keypair, leader_info: &NodeInfo) {
if retry_get_balance(client, &keypair.pubkey(), None).is_none() {
let mut drone_addr = leader_info.tpu; let mut drone_addr = leader_info.tpu;
drone_addr.set_port(DRONE_PORT); drone_addr.set_port(DRONE_PORT);
@ -233,65 +350,6 @@ impl Replicator {
} }
}; };
} }
info!("Done downloading ledger at {}", ledger_path.unwrap());
let ledger_path = Path::new(ledger_path.unwrap());
let ledger_data_file_encrypted = ledger_path.join("ledger.enc");
#[cfg(feature = "chacha")]
{
let mut ivec = [0u8; CHACHA_BLOCK_SIZE];
ivec[0..4].copy_from_slice(&[2, 3, 4, 5]);
chacha_cbc_encrypt_ledger(
&db_ledger,
entry_height,
&ledger_data_file_encrypted,
&mut ivec,
)?;
}
info!("Done encrypting the ledger");
let sampling_offsets = [0, 1, 2, 3];
match sample_file(&ledger_data_file_encrypted, &sampling_offsets) {
Ok(hash) => {
let last_id = client.get_last_id();
info!("sampled hash: {}", hash);
let tx =
Transaction::storage_new_mining_proof(&keypair, hash, last_id, entry_height);
client.transfer_signed(&tx).expect("transfer didn't work!");
}
Err(e) => info!("Error occurred while sampling: {:?}", e),
}
Ok(Self {
gossip_service,
fetch_stage,
t_window,
retransmit_receiver,
exit,
})
}
pub fn close(self) {
self.exit.store(true, Ordering::Relaxed);
self.join()
}
pub fn join(self) {
self.gossip_service.join().unwrap();
self.fetch_stage.join().unwrap();
self.t_window.join().unwrap();
// Drain the queue here to prevent self.retransmit_receiver from being dropped
// before the window_service thread is joined
let mut retransmit_queue_count = 0;
while let Ok(_blob) = self.retransmit_receiver.recv_timeout(Duration::new(1, 0)) {
retransmit_queue_count += 1;
}
debug!("retransmit channel count: {}", retransmit_queue_count);
} }
} }

View File

@ -454,6 +454,7 @@ mod tests {
use crate::leader_scheduler::LeaderScheduler; use crate::leader_scheduler::LeaderScheduler;
use crate::mint::Mint; use crate::mint::Mint;
use crate::rpc_request::get_rpc_request_str; use crate::rpc_request::get_rpc_request_str;
use crate::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use crate::vote_signer_proxy::VoteSignerProxy; use crate::vote_signer_proxy::VoteSignerProxy;
use bincode::serialize; use bincode::serialize;
use reqwest; use reqwest;
@ -749,6 +750,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));

View File

@ -56,10 +56,10 @@ macro_rules! cross_boundary {
}; };
} }
const NUM_HASHES_FOR_STORAGE_ROTATE: u64 = 1024; pub const STORAGE_ROTATE_TEST_COUNT: u64 = 128;
// TODO: some way to dynamically size NUM_IDENTITIES // TODO: some way to dynamically size NUM_IDENTITIES
const NUM_IDENTITIES: usize = 1024; const NUM_IDENTITIES: usize = 1024;
const NUM_SAMPLES: usize = 4; pub const NUM_STORAGE_SAMPLES: usize = 4;
pub const ENTRIES_PER_SEGMENT: u64 = 16; pub const ENTRIES_PER_SEGMENT: u64 = 16;
const KEY_SIZE: usize = 64; const KEY_SIZE: usize = 64;
@ -139,6 +139,7 @@ impl StorageStage {
keypair: Arc<Keypair>, keypair: Arc<Keypair>,
exit: Arc<AtomicBool>, exit: Arc<AtomicBool>,
entry_height: u64, entry_height: u64,
storage_rotate_count: u64,
) -> Self { ) -> Self {
debug!("storage_stage::new: entry_height: {}", entry_height); debug!("storage_stage::new: entry_height: {}", entry_height);
storage_state.state.write().unwrap().entry_height = entry_height; storage_state.state.write().unwrap().entry_height = entry_height;
@ -160,6 +161,7 @@ impl StorageStage {
&mut poh_height, &mut poh_height,
&mut entry_height, &mut entry_height,
&mut current_key, &mut current_key,
storage_rotate_count,
) { ) {
match e { match e {
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break, Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
@ -211,7 +213,7 @@ impl StorageStage {
); );
let mut samples = vec![]; let mut samples = vec![];
for _ in 0..NUM_SAMPLES { for _ in 0..NUM_STORAGE_SAMPLES {
samples.push(rng.gen_range(0, 10)); samples.push(rng.gen_range(0, 10));
} }
debug!("generated samples: {:?}", samples); debug!("generated samples: {:?}", samples);
@ -256,6 +258,7 @@ impl StorageStage {
poh_height: &mut u64, poh_height: &mut u64,
entry_height: &mut u64, entry_height: &mut u64,
current_key_idx: &mut usize, current_key_idx: &mut usize,
storage_rotate_count: u64,
) -> Result<()> { ) -> Result<()> {
let timeout = Duration::new(1, 0); let timeout = Duration::new(1, 0);
let entries = entry_receiver.recv_timeout(timeout)?; let entries = entry_receiver.recv_timeout(timeout)?;
@ -306,7 +309,7 @@ impl StorageStage {
} }
} }
} }
if cross_boundary!(*poh_height, entry.num_hashes, NUM_HASHES_FOR_STORAGE_ROTATE) { if cross_boundary!(*poh_height, entry.num_hashes, storage_rotate_count) {
info!( info!(
"crosses sending at poh_height: {} entry_height: {}! hashes: {}", "crosses sending at poh_height: {} entry_height: {}! hashes: {}",
*poh_height, entry_height, entry.num_hashes *poh_height, entry_height, entry.num_hashes
@ -343,7 +346,9 @@ mod tests {
use crate::service::Service; use crate::service::Service;
use crate::storage_stage::StorageState; use crate::storage_stage::StorageState;
use crate::storage_stage::NUM_IDENTITIES; use crate::storage_stage::NUM_IDENTITIES;
use crate::storage_stage::{get_identity_index_from_signature, StorageStage}; use crate::storage_stage::{
get_identity_index_from_signature, StorageStage, STORAGE_ROTATE_TEST_COUNT,
};
use rayon::prelude::*; use rayon::prelude::*;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::hash::Hasher; use solana_sdk::hash::Hasher;
@ -373,6 +378,7 @@ mod tests {
keypair, keypair,
exit.clone(), exit.clone(),
0, 0,
STORAGE_ROTATE_TEST_COUNT,
); );
exit.store(true, Ordering::Relaxed); exit.store(true, Ordering::Relaxed);
storage_stage.join().unwrap(); storage_stage.join().unwrap();
@ -392,7 +398,7 @@ mod tests {
1, 1,
); );
let entries = make_tiny_test_entries(128); let entries = make_tiny_test_entries(64);
let db_ledger = DbLedger::open(&ledger_path).unwrap(); let db_ledger = DbLedger::open(&ledger_path).unwrap();
db_ledger db_ledger
.write_entries(DEFAULT_SLOT_HEIGHT, genesis_entries.len() as u64, &entries) .write_entries(DEFAULT_SLOT_HEIGHT, genesis_entries.len() as u64, &entries)
@ -407,6 +413,7 @@ mod tests {
keypair, keypair,
exit.clone(), exit.clone(),
0, 0,
STORAGE_ROTATE_TEST_COUNT,
); );
storage_entry_sender.send(entries.clone()).unwrap(); storage_entry_sender.send(entries.clone()).unwrap();
@ -471,6 +478,7 @@ mod tests {
keypair, keypair,
exit.clone(), exit.clone(),
0, 0,
STORAGE_ROTATE_TEST_COUNT,
); );
storage_entry_sender.send(entries.clone()).unwrap(); storage_entry_sender.send(entries.clone()).unwrap();

View File

@ -441,6 +441,7 @@ mod tests {
use crate::fullnode::Fullnode; use crate::fullnode::Fullnode;
use crate::leader_scheduler::LeaderScheduler; use crate::leader_scheduler::LeaderScheduler;
use crate::mint::Mint; use crate::mint::Mint;
use crate::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use crate::vote_signer_proxy::VoteSignerProxy; use crate::vote_signer_proxy::VoteSignerProxy;
use bincode::deserialize; use bincode::deserialize;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
@ -483,6 +484,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));
@ -539,6 +541,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
//TODO: remove this sleep, or add a retry so CI is stable //TODO: remove this sleep, or add a retry so CI is stable
sleep(Duration::from_millis(300)); sleep(Duration::from_millis(300));
@ -600,6 +603,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(300)); sleep(Duration::from_millis(300));
@ -650,6 +654,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(300)); sleep(Duration::from_millis(300));
@ -746,6 +751,7 @@ mod tests {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));

View File

@ -65,6 +65,7 @@ impl Tvu {
cluster_info: &Arc<RwLock<ClusterInfo>>, cluster_info: &Arc<RwLock<ClusterInfo>>,
sockets: Sockets, sockets: Sockets,
db_ledger: Arc<DbLedger>, db_ledger: Arc<DbLedger>,
storage_rotate_count: u64,
) -> Self { ) -> Self {
let exit = Arc::new(AtomicBool::new(false)); let exit = Arc::new(AtomicBool::new(false));
let keypair: Arc<Keypair> = cluster_info let keypair: Arc<Keypair> = cluster_info
@ -119,6 +120,7 @@ impl Tvu {
keypair, keypair,
exit.clone(), exit.clone(),
entry_height, entry_height,
storage_rotate_count,
); );
Tvu { Tvu {
@ -179,6 +181,7 @@ pub mod tests {
use crate::mint::Mint; use crate::mint::Mint;
use crate::packet::SharedBlob; use crate::packet::SharedBlob;
use crate::service::Service; use crate::service::Service;
use crate::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use crate::streamer; use crate::streamer;
use crate::tvu::{Sockets, Tvu}; use crate::tvu::{Sockets, Tvu};
use crate::vote_signer_proxy::VoteSignerProxy; use crate::vote_signer_proxy::VoteSignerProxy;
@ -284,6 +287,7 @@ pub mod tests {
} }
}, },
Arc::new(db_ledger), Arc::new(db_ledger),
STORAGE_ROTATE_TEST_COUNT,
); );
let mut alice_ref_balance = starting_balance; let mut alice_ref_balance = starting_balance;

View File

@ -14,8 +14,10 @@ use solana::entry::Entry;
use solana::fullnode::Fullnode; use solana::fullnode::Fullnode;
use solana::leader_scheduler::LeaderScheduler; use solana::leader_scheduler::LeaderScheduler;
use solana::replicator::Replicator; use solana::replicator::Replicator;
use solana::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use solana::streamer::blob_receiver; use solana::streamer::blob_receiver;
use solana::vote_signer_proxy::VoteSignerProxy; use solana::vote_signer_proxy::VoteSignerProxy;
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction; use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
@ -24,6 +26,7 @@ use std::fs::remove_dir_all;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::sync::Arc; use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
#[test] #[test]
@ -38,7 +41,8 @@ fn test_replicator_startup() {
let leader_info = leader_node.info.clone(); let leader_info = leader_node.info.clone();
let leader_ledger_path = "replicator_test_leader_ledger"; let leader_ledger_path = "replicator_test_leader_ledger";
let (mint, leader_ledger_path) = create_tmp_genesis(leader_ledger_path, 100, leader_info.id, 1); let (mint, leader_ledger_path) =
create_tmp_genesis(leader_ledger_path, 1_000_000_000, leader_info.id, 1);
let validator_ledger_path = let validator_ledger_path =
tmp_copy_ledger(&leader_ledger_path, "replicator_test_validator_ledger"); tmp_copy_ledger(&leader_ledger_path, "replicator_test_validator_ledger");
@ -47,7 +51,7 @@ fn test_replicator_startup() {
let signer_proxy = let signer_proxy =
VoteSignerProxy::new(&leader_keypair, Box::new(LocalVoteSigner::default())); VoteSignerProxy::new(&leader_keypair, Box::new(LocalVoteSigner::default()));
let leader = Fullnode::new( let leader = Fullnode::new_with_storage_rotate(
leader_node, leader_node,
&leader_ledger_path, &leader_ledger_path,
leader_keypair, leader_keypair,
@ -56,16 +60,27 @@ fn test_replicator_startup() {
false, false,
LeaderScheduler::from_bootstrap_leader(leader_info.id.clone()), LeaderScheduler::from_bootstrap_leader(leader_info.id.clone()),
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
let validator_keypair = Arc::new(Keypair::new()); let validator_keypair = Arc::new(Keypair::new());
let signer_proxy = let signer_proxy =
VoteSignerProxy::new(&validator_keypair, Box::new(LocalVoteSigner::default())); VoteSignerProxy::new(&validator_keypair, Box::new(LocalVoteSigner::default()));
let mut leader_client = mk_client(&leader_info);
let last_id = leader_client.get_last_id();
let mut leader_client = mk_client(&leader_info);
leader_client
.transfer(10, &mint.keypair(), validator_keypair.pubkey(), &last_id)
.unwrap();
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey()); let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
#[cfg(feature = "chacha")] #[cfg(feature = "chacha")]
let validator_node_info = validator_node.info.clone(); let validator_node_info = validator_node.info.clone();
let validator = Fullnode::new( let validator = Fullnode::new_with_storage_rotate(
validator_node, validator_node,
&validator_ledger_path, &validator_ledger_path,
validator_keypair, validator_keypair,
@ -74,19 +89,26 @@ fn test_replicator_startup() {
false, false,
LeaderScheduler::from_bootstrap_leader(leader_info.id), LeaderScheduler::from_bootstrap_leader(leader_info.id),
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
let mut leader_client = mk_client(&leader_info);
let bob = Keypair::new(); let bob = Keypair::new();
let last_id = leader_client.get_last_id(); info!("starting transfers..");
leader_client
.transfer(1, &mint.keypair(), bob.pubkey(), &last_id) for _ in 0..64 {
.unwrap(); let last_id = leader_client.get_last_id();
leader_client
.transfer(1, &mint.keypair(), bob.pubkey(), &last_id)
.unwrap();
sleep(Duration::from_millis(200));
}
let replicator_keypair = Keypair::new(); let replicator_keypair = Keypair::new();
info!("giving replicator tokens..");
let last_id = leader_client.get_last_id();
// Give the replicator some tokens // Give the replicator some tokens
let amount = 1; let amount = 1;
let mut tx = Transaction::system_new( let mut tx = Transaction::system_new(
@ -113,11 +135,13 @@ fn test_replicator_startup() {
) )
.unwrap(); .unwrap();
info!("started replicator..");
// Create a client which downloads from the replicator and see that it // Create a client which downloads from the replicator and see that it
// can respond with blobs. // can respond with blobs.
let tn = Node::new_localhost(); let tn = Node::new_localhost();
let cluster_info = ClusterInfo::new(tn.info.clone()); let cluster_info = ClusterInfo::new(tn.info.clone());
let repair_index = 1; let repair_index = replicator.entry_height();
let req = cluster_info let req = cluster_info
.window_index_request_bytes(repair_index) .window_index_request_bytes(repair_index)
.unwrap(); .unwrap();
@ -132,7 +156,7 @@ fn test_replicator_startup() {
tn.info.id, replicator_info.gossip tn.info.id, replicator_info.gossip
); );
let mut num_txs = 0; let mut received_blob = false;
for _ in 0..5 { for _ in 0..5 {
repair_socket.send_to(&req, replicator_info.gossip).unwrap(); repair_socket.send_to(&req, replicator_info.gossip).unwrap();
@ -144,7 +168,8 @@ fn test_replicator_startup() {
assert!(br.index().unwrap() == repair_index); assert!(br.index().unwrap() == repair_index);
let entry: Entry = deserialize(&br.data()[..br.meta.size]).unwrap(); let entry: Entry = deserialize(&br.data()[..br.meta.size]).unwrap();
info!("entry: {:?}", entry); info!("entry: {:?}", entry);
num_txs = entry.transactions.len(); assert_ne!(entry.id, Hash::default());
received_blob = true;
} }
break; break;
} }
@ -152,6 +177,8 @@ fn test_replicator_startup() {
exit.store(true, Ordering::Relaxed); exit.store(true, Ordering::Relaxed);
t_receiver.join().unwrap(); t_receiver.join().unwrap();
assert!(received_blob);
// The replicator will not submit storage proofs if // The replicator will not submit storage proofs if
// chacha is not enabled // chacha is not enabled
#[cfg(feature = "chacha")] #[cfg(feature = "chacha")]
@ -159,10 +186,14 @@ fn test_replicator_startup() {
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler}; use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
use std::thread::sleep; use std::thread::sleep;
info!(
"looking for pubkeys for entry: {}",
replicator.entry_height()
);
let rpc_client = RpcClient::new_from_socket(validator_node_info.rpc); let rpc_client = RpcClient::new_from_socket(validator_node_info.rpc);
let mut non_zero_pubkeys = false; let mut non_zero_pubkeys = false;
for _ in 0..30 { for _ in 0..60 {
let params = json!([0]); let params = json!([replicator.entry_height()]);
let pubkeys = rpc_client let pubkeys = rpc_client
.make_rpc_request(1, RpcRequest::GetStoragePubkeysForEntryHeight, Some(params)) .make_rpc_request(1, RpcRequest::GetStoragePubkeysForEntryHeight, Some(params))
.unwrap(); .unwrap();
@ -176,9 +207,6 @@ fn test_replicator_startup() {
assert!(non_zero_pubkeys); assert!(non_zero_pubkeys);
} }
// Check that some ledger was downloaded
assert!(num_txs != 0);
replicator.close(); replicator.close();
validator.exit(); validator.exit();
leader.close().expect("Expected successful node closure"); leader.close().expect("Expected successful node closure");

View File

@ -7,6 +7,7 @@ use solana::fullnode::Fullnode;
use solana::leader_scheduler::LeaderScheduler; use solana::leader_scheduler::LeaderScheduler;
use solana::mint::Mint; use solana::mint::Mint;
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler}; use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
use solana::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use solana::vote_signer_proxy::VoteSignerProxy; use solana::vote_signer_proxy::VoteSignerProxy;
use solana_drone::drone::run_local_drone; use solana_drone::drone::run_local_drone;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
@ -62,6 +63,7 @@ fn test_wallet_timestamp_tx() {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));
@ -161,6 +163,7 @@ fn test_wallet_witness_tx() {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));
@ -256,6 +259,7 @@ fn test_wallet_cancel_tx() {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));

View File

@ -6,6 +6,7 @@ use solana::fullnode::Fullnode;
use solana::leader_scheduler::LeaderScheduler; use solana::leader_scheduler::LeaderScheduler;
use solana::mint::Mint; use solana::mint::Mint;
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler}; use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
use solana::storage_stage::STORAGE_ROTATE_TEST_COUNT;
use solana::vote_signer_proxy::VoteSignerProxy; use solana::vote_signer_proxy::VoteSignerProxy;
use solana_drone::drone::run_local_drone; use solana_drone::drone::run_local_drone;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
@ -48,6 +49,7 @@ fn test_wallet_request_airdrop() {
&ledger_path, &ledger_path,
false, false,
None, None,
STORAGE_ROTATE_TEST_COUNT,
); );
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));