diff --git a/core/src/replicator.rs b/core/src/replicator.rs index 19c104e0d9..80fb69d500 100644 --- a/core/src/replicator.rs +++ b/core/src/replicator.rs @@ -14,6 +14,10 @@ use crate::window_service::WindowService; use bincode::deserialize; use rand::thread_rng; use rand::Rng; +#[cfg(feature = "chacha")] +use rand::SeedableRng; +#[cfg(feature = "chacha")] +use rand_chacha::ChaChaRng; use solana_client::rpc_client::RpcClient; use solana_client::rpc_request::RpcRequest; use solana_client::thin_client::ThinClient; @@ -64,6 +68,8 @@ pub struct Replicator { num_chacha_blocks: usize, #[cfg(feature = "chacha")] blocktree: Arc, + #[cfg(feature = "chacha")] + rng: ChaChaRng, } pub(crate) fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result { @@ -261,6 +267,11 @@ impl Replicator { //always push this last thread_handles.push(t_replicate); + let mut rng_seed = [0u8; 32]; + rng_seed.copy_from_slice(&signature.to_bytes()[0..32]); + #[cfg(feature = "chacha")] + let rng = ChaChaRng::from_seed(rng_seed); + Ok(Self { gossip_service, fetch_stage, @@ -280,6 +291,8 @@ impl Replicator { num_chacha_blocks: 0, #[cfg(feature = "chacha")] blocktree, + #[cfg(feature = "chacha")] + rng, }) } @@ -288,13 +301,15 @@ impl Replicator { self.thread_handles.pop().unwrap().join().unwrap(); self.encrypt_ledger() .expect("ledger encrypt not successful"); + let mut proof_index = 0; loop { self.create_sampling_offsets(); + proof_index += 1; if let Err(err) = self.sample_file_to_create_mining_hash() { warn!("Error sampling file, exiting: {:?}", err); break; } - self.submit_mining_proof(); + self.submit_mining_proof(proof_index); // TODO: Replicators should be submitting proofs as fast as possible sleep(Duration::from_secs(2)); } @@ -381,15 +396,9 @@ impl Replicator { #[cfg(feature = "chacha")] { use crate::storage_stage::NUM_STORAGE_SAMPLES; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaChaRng; - - let mut rng_seed = [0u8; 32]; - rng_seed.copy_from_slice(&self.signature.to_bytes()[0..32]); - let mut rng = ChaChaRng::from_seed(rng_seed); for _ in 0..NUM_STORAGE_SAMPLES { self.sampling_offsets - .push(rng.gen_range(0, self.num_chacha_blocks) as u64); + .push(self.rng.gen_range(0, self.num_chacha_blocks) as u64); } } } @@ -438,7 +447,7 @@ impl Replicator { Ok(()) } - fn submit_mining_proof(&self) { + fn submit_mining_proof(&self, proof_index: u64) { // No point if we've got no storage account... let nodes = self.cluster_info.read().unwrap().tvu_peers(); let client = crate::gossip_service::get_client(&nodes); @@ -457,6 +466,7 @@ impl Replicator { self.hash, self.slot, Signature::new(&self.signature.to_bytes()), + proof_index, ); let message = Message::new_with_payer(vec![instruction], Some(&self.keypair.pubkey())); let mut transaction = Transaction::new( diff --git a/core/src/storage_stage.rs b/core/src/storage_stage.rs index a3eb94245b..7a896c0386 100644 --- a/core/src/storage_stage.rs +++ b/core/src/storage_stage.rs @@ -366,6 +366,7 @@ impl StorageStage { slot: proof_slot, signature, sha_state, + .. }) => { if proof_slot < slot { { @@ -701,6 +702,7 @@ mod tests { Hash::default(), 0, keypair.sign_message(b"test"), + 0, ); let mining_proof_tx = Transaction::new_unsigned_instructions(vec![mining_proof_ix]); let mining_txs = vec![mining_proof_tx]; diff --git a/programs/storage_api/src/storage_instruction.rs b/programs/storage_api/src/storage_instruction.rs index e91af834ae..569f2ac2a2 100644 --- a/programs/storage_api/src/storage_instruction.rs +++ b/programs/storage_api/src/storage_instruction.rs @@ -22,6 +22,7 @@ pub enum StorageInstruction { sha_state: Hash, slot: u64, signature: Signature, + proof_index: u64, }, AdvertiseStorageRecentBlockhash { hash: Hash, @@ -109,11 +110,13 @@ pub fn mining_proof( sha_state: Hash, slot: u64, signature: Signature, + proof_index: u64, ) -> Instruction { let storage_instruction = StorageInstruction::SubmitMiningProof { sha_state, slot, signature, + proof_index, }; let account_metas = vec![AccountMeta::new(*storage_pubkey, true)]; Instruction::new(id(), &storage_instruction, account_metas) diff --git a/programs/storage_api/src/storage_processor.rs b/programs/storage_api/src/storage_processor.rs index 9ea5b7ff14..2f0ea35c5f 100644 --- a/programs/storage_api/src/storage_processor.rs +++ b/programs/storage_api/src/storage_processor.rs @@ -43,6 +43,7 @@ pub fn process_instruction( sha_state, slot, signature, + .. } => { if me_unsigned || !rest.is_empty() { // This instruction must be signed by `me` @@ -154,6 +155,7 @@ mod tests { Hash::default(), SLOTS_PER_SEGMENT, Signature::default(), + 0, ); // the proof is for slot 16, which is in segment 0, need to move the tick height into segment 2 let ticks_till_next_segment = TICKS_IN_SEGMENT * 2; @@ -197,7 +199,7 @@ mod tests { let mut accounts = [Account::default()]; let ix = - storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default()); + storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default(), 0); // move tick height into segment 1 let ticks_till_next_segment = TICKS_IN_SEGMENT + 1; @@ -217,7 +219,7 @@ mod tests { accounts[1].data.resize(STORAGE_ACCOUNT_SPACE as usize, 0); let ix = - storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default()); + storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default(), 0); // submitting a proof for a slot in the past, so this should fail assert!(test_instruction(&ix, &mut accounts, 0).is_err()); @@ -235,7 +237,7 @@ mod tests { } let ix = - storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default()); + storage_instruction::mining_proof(&pubkey, Hash::default(), 0, Signature::default(), 0); // move tick height into segment 1 let ticks_till_next_segment = TICKS_IN_SEGMENT + 1; @@ -493,6 +495,7 @@ mod tests { sha_state, slot, Signature::default(), + 0, )], Some(&mint_keypair.pubkey()), ); @@ -586,6 +589,7 @@ mod tests { Hash::default(), slot, Signature::default(), + 0, )], Some(&mint_pubkey), );