Add newly completed slots signal to Blocktree (#4225)
* Add channel to blocktree for communicating when slots are completed * Refactor RepairService options into a RepairStrategy
This commit is contained in:
		| @@ -28,7 +28,7 @@ use std::cmp; | |||||||
| use std::fs; | use std::fs; | ||||||
| use std::io; | use std::io; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; | use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; | ||||||
| use std::sync::{Arc, RwLock}; | use std::sync::{Arc, RwLock}; | ||||||
|  |  | ||||||
| pub use self::meta::*; | pub use self::meta::*; | ||||||
| @@ -63,6 +63,10 @@ db_imports! {rocks, Rocks, "rocksdb"} | |||||||
| #[cfg(feature = "kvstore")] | #[cfg(feature = "kvstore")] | ||||||
| db_imports! {kvs, Kvs, "kvstore"} | db_imports! {kvs, Kvs, "kvstore"} | ||||||
|  |  | ||||||
|  | pub const MAX_COMPLETED_SLOTS_IN_CHANNEL: usize = 100_000; | ||||||
|  |  | ||||||
|  | pub type CompletedSlotsReceiver = Receiver<Vec<u64>>; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum BlocktreeError { | pub enum BlocktreeError { | ||||||
|     BlobForIndexExists, |     BlobForIndexExists, | ||||||
| @@ -83,6 +87,7 @@ pub struct Blocktree { | |||||||
|     batch_processor: Arc<RwLock<BatchProcessor>>, |     batch_processor: Arc<RwLock<BatchProcessor>>, | ||||||
|     session: Arc<erasure::Session>, |     session: Arc<erasure::Session>, | ||||||
|     pub new_blobs_signals: Vec<SyncSender<bool>>, |     pub new_blobs_signals: Vec<SyncSender<bool>>, | ||||||
|  |     pub completed_slots_senders: Vec<SyncSender<Vec<u64>>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| // Column family for metadata about a leader slot | // Column family for metadata about a leader slot | ||||||
| @@ -141,15 +146,21 @@ impl Blocktree { | |||||||
|             session, |             session, | ||||||
|             new_blobs_signals: vec![], |             new_blobs_signals: vec![], | ||||||
|             batch_processor, |             batch_processor, | ||||||
|  |             completed_slots_senders: vec![], | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn open_with_signal(ledger_path: &str) -> Result<(Self, Receiver<bool>)> { |     pub fn open_with_signal( | ||||||
|  |         ledger_path: &str, | ||||||
|  |     ) -> Result<(Self, Receiver<bool>, CompletedSlotsReceiver)> { | ||||||
|         let mut blocktree = Self::open(ledger_path)?; |         let mut blocktree = Self::open(ledger_path)?; | ||||||
|         let (signal_sender, signal_receiver) = sync_channel(1); |         let (signal_sender, signal_receiver) = sync_channel(1); | ||||||
|  |         let (completed_slots_sender, completed_slots_receiver) = | ||||||
|  |             sync_channel(MAX_COMPLETED_SLOTS_IN_CHANNEL); | ||||||
|         blocktree.new_blobs_signals = vec![signal_sender]; |         blocktree.new_blobs_signals = vec![signal_sender]; | ||||||
|  |         blocktree.completed_slots_senders = vec![completed_slots_sender]; | ||||||
|  |  | ||||||
|         Ok((blocktree, signal_receiver)) |         Ok((blocktree, signal_receiver, completed_slots_receiver)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn destroy(ledger_path: &str) -> Result<()> { |     pub fn destroy(ledger_path: &str) -> Result<()> { | ||||||
| @@ -340,11 +351,17 @@ impl Blocktree { | |||||||
|         // Handle chaining for the working set |         // Handle chaining for the working set | ||||||
|         handle_chaining(&db, &mut write_batch, &slot_meta_working_set)?; |         handle_chaining(&db, &mut write_batch, &slot_meta_working_set)?; | ||||||
|         let mut should_signal = false; |         let mut should_signal = false; | ||||||
|  |         let mut newly_completed_slots = vec![]; | ||||||
|  |  | ||||||
|         // Check if any metadata was changed, if so, insert the new version of the |         // Check if any metadata was changed, if so, insert the new version of the | ||||||
|         // metadata into the write batch |         // metadata into the write batch | ||||||
|         for (slot, (meta, meta_backup)) in slot_meta_working_set.iter() { |         for (slot, (meta, meta_backup)) in slot_meta_working_set.iter() { | ||||||
|             let meta: &SlotMeta = &RefCell::borrow(&*meta); |             let meta: &SlotMeta = &RefCell::borrow(&*meta); | ||||||
|  |             if !self.completed_slots_senders.is_empty() | ||||||
|  |                 && is_newly_completed_slot(meta, meta_backup) | ||||||
|  |             { | ||||||
|  |                 newly_completed_slots.push(*slot); | ||||||
|  |             } | ||||||
|             // Check if the working copy of the metadata has changed |             // Check if the working copy of the metadata has changed | ||||||
|             if Some(meta) != meta_backup.as_ref() { |             if Some(meta) != meta_backup.as_ref() { | ||||||
|                 should_signal = should_signal || slot_has_updates(meta, &meta_backup); |                 should_signal = should_signal || slot_has_updates(meta, &meta_backup); | ||||||
| @@ -356,13 +373,38 @@ impl Blocktree { | |||||||
|             write_batch.put::<cf::ErasureMeta>((slot, set_index), &erasure_meta)?; |             write_batch.put::<cf::ErasureMeta>((slot, set_index), &erasure_meta)?; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         batch_processor.write(write_batch)?; | ||||||
|  |  | ||||||
|         if should_signal { |         if should_signal { | ||||||
|             for signal in self.new_blobs_signals.iter() { |             for signal in &self.new_blobs_signals { | ||||||
|                 let _ = signal.try_send(true); |                 let _ = signal.try_send(true); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         batch_processor.write(write_batch)?; |         if !self.completed_slots_senders.is_empty() && !newly_completed_slots.is_empty() { | ||||||
|  |             let mut slots: Vec<_> = (0..self.completed_slots_senders.len() - 1) | ||||||
|  |                 .map(|_| newly_completed_slots.clone()) | ||||||
|  |                 .collect(); | ||||||
|  |  | ||||||
|  |             slots.push(newly_completed_slots); | ||||||
|  |  | ||||||
|  |             for (signal, slots) in self.completed_slots_senders.iter().zip(slots.into_iter()) { | ||||||
|  |                 let res = signal.try_send(slots); | ||||||
|  |                 if let Err(TrySendError::Full(_)) = res { | ||||||
|  |                     solana_metrics::submit( | ||||||
|  |                         solana_metrics::influxdb::Point::new("blocktree_error") | ||||||
|  |                             .add_field( | ||||||
|  |                                 "error", | ||||||
|  |                                 solana_metrics::influxdb::Value::String( | ||||||
|  |                                     "Unable to send newly completed slot because channel is full" | ||||||
|  |                                         .to_string(), | ||||||
|  |                                 ), | ||||||
|  |                             ) | ||||||
|  |                             .to_owned(), | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -880,7 +922,7 @@ fn insert_data_blob<'a>( | |||||||
|     slot_meta.received = cmp::max(blob_index + 1, slot_meta.received); |     slot_meta.received = cmp::max(blob_index + 1, slot_meta.received); | ||||||
|     slot_meta.consumed = new_consumed; |     slot_meta.consumed = new_consumed; | ||||||
|     slot_meta.last_index = { |     slot_meta.last_index = { | ||||||
|         // If the last slot hasn't been set before, then |         // If the last index in the slot hasn't been set before, then | ||||||
|         // set it to this blob index |         // set it to this blob index | ||||||
|         if slot_meta.last_index == std::u64::MAX { |         if slot_meta.last_index == std::u64::MAX { | ||||||
|             if blob_to_insert.is_last_in_slot() { |             if blob_to_insert.is_last_in_slot() { | ||||||
| @@ -1123,9 +1165,8 @@ fn handle_chaining_for_slot( | |||||||
|         .expect("Slot must exist in the working_set hashmap"); |         .expect("Slot must exist in the working_set hashmap"); | ||||||
|  |  | ||||||
|     { |     { | ||||||
|         let is_orphaned = meta_backup.is_some() && is_orphan(meta_backup.as_ref().unwrap()); |  | ||||||
|  |  | ||||||
|         let mut meta_mut = meta.borrow_mut(); |         let mut meta_mut = meta.borrow_mut(); | ||||||
|  |         let was_orphan_slot = meta_backup.is_some() && is_orphan(meta_backup.as_ref().unwrap()); | ||||||
|  |  | ||||||
|         // If: |         // If: | ||||||
|         // 1) This is a new slot |         // 1) This is a new slot | ||||||
| @@ -1137,27 +1178,32 @@ fn handle_chaining_for_slot( | |||||||
|             // Check if the slot represented by meta_mut is either a new slot or a orphan. |             // Check if the slot represented by meta_mut is either a new slot or a orphan. | ||||||
|             // In both cases we need to run the chaining logic b/c the parent on the slot was |             // In both cases we need to run the chaining logic b/c the parent on the slot was | ||||||
|             // previously unknown. |             // previously unknown. | ||||||
|             if meta_backup.is_none() || is_orphaned { |             if meta_backup.is_none() || was_orphan_slot { | ||||||
|                 let prev_slot_meta = |                 let prev_slot_meta = | ||||||
|                     find_slot_meta_else_create(db, working_set, new_chained_slots, prev_slot)?; |                     find_slot_meta_else_create(db, working_set, new_chained_slots, prev_slot)?; | ||||||
|  |  | ||||||
|                 // This is a newly inserted slot so run the chaining logic |                 // This is a newly inserted slot/orphan so run the chaining logic to link it to a | ||||||
|  |                 // newly discovered parent | ||||||
|                 chain_new_slot_to_prev_slot(&mut prev_slot_meta.borrow_mut(), slot, &mut meta_mut); |                 chain_new_slot_to_prev_slot(&mut prev_slot_meta.borrow_mut(), slot, &mut meta_mut); | ||||||
|  |  | ||||||
|  |                 // If the parent of `slot` is a newly inserted orphan, insert it into the orphans | ||||||
|  |                 // column family | ||||||
|                 if is_orphan(&RefCell::borrow(&*prev_slot_meta)) { |                 if is_orphan(&RefCell::borrow(&*prev_slot_meta)) { | ||||||
|                     write_batch.put::<cf::Orphans>(prev_slot, &true)?; |                     write_batch.put::<cf::Orphans>(prev_slot, &true)?; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // At this point this slot has received a parent, so no longer a orphan |         // At this point this slot has received a parent, so it's no longer an orphan | ||||||
|         if is_orphaned { |         if was_orphan_slot { | ||||||
|             write_batch.delete::<cf::Orphans>(slot)?; |             write_batch.delete::<cf::Orphans>(slot)?; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // This is a newly inserted slot and slot.is_connected is true, so update all |     // If this is a newly inserted slot, then we know the children of this slot were not previously | ||||||
|     // child slots so that their `is_connected` = true |     // connected to the trunk of the ledger. Thus if slot.is_connected is now true, we need to | ||||||
|  |     // update all child slots with `is_connected` = true because these children are also now newly | ||||||
|  |     // connected to to trunk of the the ledger | ||||||
|     let should_propagate_is_connected = |     let should_propagate_is_connected = | ||||||
|         is_newly_completed_slot(&RefCell::borrow(&*meta), meta_backup) |         is_newly_completed_slot(&RefCell::borrow(&*meta), meta_backup) | ||||||
|             && RefCell::borrow(&*meta).is_connected; |             && RefCell::borrow(&*meta).is_connected; | ||||||
| @@ -1238,7 +1284,6 @@ fn chain_new_slot_to_prev_slot( | |||||||
| fn is_newly_completed_slot(slot_meta: &SlotMeta, backup_slot_meta: &Option<SlotMeta>) -> bool { | fn is_newly_completed_slot(slot_meta: &SlotMeta, backup_slot_meta: &Option<SlotMeta>) -> bool { | ||||||
|     slot_meta.is_full() |     slot_meta.is_full() | ||||||
|         && (backup_slot_meta.is_none() |         && (backup_slot_meta.is_none() | ||||||
|             || is_orphan(&backup_slot_meta.as_ref().unwrap()) |  | ||||||
|             || slot_meta.consumed != backup_slot_meta.as_ref().unwrap().consumed) |             || slot_meta.consumed != backup_slot_meta.as_ref().unwrap().consumed) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2112,7 +2157,7 @@ pub mod tests { | |||||||
|     pub fn test_new_blobs_signal() { |     pub fn test_new_blobs_signal() { | ||||||
|         // Initialize ledger |         // Initialize ledger | ||||||
|         let ledger_path = get_tmp_ledger_path("test_new_blobs_signal"); |         let ledger_path = get_tmp_ledger_path("test_new_blobs_signal"); | ||||||
|         let (ledger, recvr) = Blocktree::open_with_signal(&ledger_path).unwrap(); |         let (ledger, recvr, _) = Blocktree::open_with_signal(&ledger_path).unwrap(); | ||||||
|         let ledger = Arc::new(ledger); |         let ledger = Arc::new(ledger); | ||||||
|  |  | ||||||
|         let entries_per_slot = 10; |         let entries_per_slot = 10; | ||||||
| @@ -2188,6 +2233,98 @@ pub mod tests { | |||||||
|         Blocktree::destroy(&ledger_path).expect("Expected successful database destruction"); |         Blocktree::destroy(&ledger_path).expect("Expected successful database destruction"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     pub fn test_completed_blobs_signal() { | ||||||
|  |         // Initialize ledger | ||||||
|  |         let ledger_path = get_tmp_ledger_path("test_completed_blobs_signal"); | ||||||
|  |         let (ledger, _, recvr) = Blocktree::open_with_signal(&ledger_path).unwrap(); | ||||||
|  |         let ledger = Arc::new(ledger); | ||||||
|  |  | ||||||
|  |         let entries_per_slot = 10; | ||||||
|  |  | ||||||
|  |         // Create blobs for slot 0 | ||||||
|  |         let (blobs, _) = make_slot_entries(0, 0, entries_per_slot); | ||||||
|  |  | ||||||
|  |         // Insert all but the first blob in the slot, should not be considered complete | ||||||
|  |         ledger | ||||||
|  |             .insert_data_blobs(&blobs[1..entries_per_slot as usize]) | ||||||
|  |             .unwrap(); | ||||||
|  |         assert!(recvr.try_recv().is_err()); | ||||||
|  |  | ||||||
|  |         // Insert first blob, slot should now be considered complete | ||||||
|  |         ledger.insert_data_blobs(once(&blobs[0])).unwrap(); | ||||||
|  |         assert_eq!(recvr.try_recv().unwrap(), vec![0]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     pub fn test_completed_blobs_signal_orphans() { | ||||||
|  |         // Initialize ledger | ||||||
|  |         let ledger_path = get_tmp_ledger_path("test_completed_blobs_signal_orphans"); | ||||||
|  |         let (ledger, _, recvr) = Blocktree::open_with_signal(&ledger_path).unwrap(); | ||||||
|  |         let ledger = Arc::new(ledger); | ||||||
|  |  | ||||||
|  |         let entries_per_slot = 10; | ||||||
|  |         let slots = vec![2, 5, 10]; | ||||||
|  |         let all_blobs = make_chaining_slot_entries(&slots[..], entries_per_slot); | ||||||
|  |  | ||||||
|  |         // Get the blobs for slot 5 chaining to slot 2 | ||||||
|  |         let (ref orphan_blobs, _) = all_blobs[1]; | ||||||
|  |  | ||||||
|  |         // Get the blobs for slot 10, chaining to slot 5 | ||||||
|  |         let (ref orphan_child, _) = all_blobs[2]; | ||||||
|  |  | ||||||
|  |         // Insert all but the first blob in the slot, should not be considered complete | ||||||
|  |         ledger | ||||||
|  |             .insert_data_blobs(&orphan_child[1..entries_per_slot as usize]) | ||||||
|  |             .unwrap(); | ||||||
|  |         assert!(recvr.try_recv().is_err()); | ||||||
|  |  | ||||||
|  |         // Insert first blob, slot should now be considered complete | ||||||
|  |         ledger.insert_data_blobs(once(&orphan_child[0])).unwrap(); | ||||||
|  |         assert_eq!(recvr.try_recv().unwrap(), vec![slots[2]]); | ||||||
|  |  | ||||||
|  |         // Insert the blobs for the orphan_slot | ||||||
|  |         ledger | ||||||
|  |             .insert_data_blobs(&orphan_blobs[1..entries_per_slot as usize]) | ||||||
|  |             .unwrap(); | ||||||
|  |         assert!(recvr.try_recv().is_err()); | ||||||
|  |  | ||||||
|  |         // Insert first blob, slot should now be considered complete | ||||||
|  |         ledger.insert_data_blobs(once(&orphan_blobs[0])).unwrap(); | ||||||
|  |         assert_eq!(recvr.try_recv().unwrap(), vec![slots[1]]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     pub fn test_completed_blobs_signal_many() { | ||||||
|  |         // Initialize ledger | ||||||
|  |         let ledger_path = get_tmp_ledger_path("test_completed_blobs_signal_many"); | ||||||
|  |         let (ledger, _, recvr) = Blocktree::open_with_signal(&ledger_path).unwrap(); | ||||||
|  |         let ledger = Arc::new(ledger); | ||||||
|  |  | ||||||
|  |         let entries_per_slot = 10; | ||||||
|  |         let mut slots = vec![2, 5, 10]; | ||||||
|  |         let all_blobs = make_chaining_slot_entries(&slots[..], entries_per_slot); | ||||||
|  |         let disconnected_slot = 4; | ||||||
|  |  | ||||||
|  |         let (ref blobs0, _) = all_blobs[0]; | ||||||
|  |         let (ref blobs1, _) = all_blobs[1]; | ||||||
|  |         let (ref blobs2, _) = all_blobs[2]; | ||||||
|  |         let (ref blobs3, _) = make_slot_entries(disconnected_slot, 1, entries_per_slot); | ||||||
|  |  | ||||||
|  |         let mut all_blobs: Vec<_> = vec![blobs0, blobs1, blobs2, blobs3] | ||||||
|  |             .into_iter() | ||||||
|  |             .flatten() | ||||||
|  |             .collect(); | ||||||
|  |  | ||||||
|  |         all_blobs.shuffle(&mut thread_rng()); | ||||||
|  |         ledger.insert_data_blobs(all_blobs).unwrap(); | ||||||
|  |         let mut result = recvr.try_recv().unwrap(); | ||||||
|  |         result.sort(); | ||||||
|  |         slots.push(disconnected_slot); | ||||||
|  |         slots.sort(); | ||||||
|  |         assert_eq!(result, slots); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     pub fn test_handle_chaining_basic() { |     pub fn test_handle_chaining_basic() { | ||||||
|         let blocktree_path = get_tmp_ledger_path("test_handle_chaining_basic"); |         let blocktree_path = get_tmp_ledger_path("test_handle_chaining_basic"); | ||||||
| @@ -3375,4 +3512,28 @@ pub mod tests { | |||||||
|  |  | ||||||
|         (blobs, entries) |         (blobs, entries) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Create blobs for slots that have a parent-child relationship defined by the input `chain` | ||||||
|  |     pub fn make_chaining_slot_entries( | ||||||
|  |         chain: &[u64], | ||||||
|  |         entries_per_slot: u64, | ||||||
|  |     ) -> Vec<(Vec<Blob>, Vec<Entry>)> { | ||||||
|  |         let mut slots_blobs_and_entries = vec![]; | ||||||
|  |         for (i, slot) in chain.iter().enumerate() { | ||||||
|  |             let parent_slot = { | ||||||
|  |                 if *slot == 0 { | ||||||
|  |                     0 | ||||||
|  |                 } else if i == 0 { | ||||||
|  |                     std::u64::MAX | ||||||
|  |                 } else { | ||||||
|  |                     chain[i - 1] | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             let result = make_slot_entries(*slot, parent_slot, entries_per_slot); | ||||||
|  |             slots_blobs_and_entries.push(result); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         slots_blobs_and_entries | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| //! The `fullnode` module hosts all the fullnode microservices. | //! The `fullnode` module hosts all the fullnode microservices. | ||||||
|  |  | ||||||
| use crate::bank_forks::BankForks; | use crate::bank_forks::BankForks; | ||||||
| use crate::blocktree::Blocktree; | use crate::blocktree::{Blocktree, CompletedSlotsReceiver}; | ||||||
| use crate::blocktree_processor::{self, BankForksInfo}; | use crate::blocktree_processor::{self, BankForksInfo}; | ||||||
| use crate::cluster_info::{ClusterInfo, Node}; | use crate::cluster_info::{ClusterInfo, Node}; | ||||||
| use crate::contact_info::ContactInfo; | use crate::contact_info::ContactInfo; | ||||||
| @@ -95,8 +95,14 @@ impl Fullnode { | |||||||
|         let id = keypair.pubkey(); |         let id = keypair.pubkey(); | ||||||
|         assert_eq!(id, node.info.id); |         assert_eq!(id, node.info.id); | ||||||
|  |  | ||||||
|         let (bank_forks, bank_forks_info, blocktree, ledger_signal_receiver, leader_schedule_cache) = |         let ( | ||||||
|             new_banks_from_blocktree(ledger_path, config.account_paths.clone()); |             bank_forks, | ||||||
|  |             bank_forks_info, | ||||||
|  |             blocktree, | ||||||
|  |             ledger_signal_receiver, | ||||||
|  |             completed_slots_receiver, | ||||||
|  |             leader_schedule_cache, | ||||||
|  |         ) = new_banks_from_blocktree(ledger_path, config.account_paths.clone()); | ||||||
|  |  | ||||||
|         let leader_schedule_cache = Arc::new(leader_schedule_cache); |         let leader_schedule_cache = Arc::new(leader_schedule_cache); | ||||||
|         let exit = Arc::new(AtomicBool::new(false)); |         let exit = Arc::new(AtomicBool::new(false)); | ||||||
| @@ -236,6 +242,7 @@ impl Fullnode { | |||||||
|             &leader_schedule_cache, |             &leader_schedule_cache, | ||||||
|             &exit, |             &exit, | ||||||
|             &genesis_blockhash, |             &genesis_blockhash, | ||||||
|  |             completed_slots_receiver, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         if config.sigverify_disabled { |         if config.sigverify_disabled { | ||||||
| @@ -290,13 +297,15 @@ pub fn new_banks_from_blocktree( | |||||||
|     Vec<BankForksInfo>, |     Vec<BankForksInfo>, | ||||||
|     Blocktree, |     Blocktree, | ||||||
|     Receiver<bool>, |     Receiver<bool>, | ||||||
|  |     CompletedSlotsReceiver, | ||||||
|     LeaderScheduleCache, |     LeaderScheduleCache, | ||||||
| ) { | ) { | ||||||
|     let genesis_block = |     let genesis_block = | ||||||
|         GenesisBlock::load(blocktree_path).expect("Expected to successfully open genesis block"); |         GenesisBlock::load(blocktree_path).expect("Expected to successfully open genesis block"); | ||||||
|  |  | ||||||
|     let (blocktree, ledger_signal_receiver) = Blocktree::open_with_signal(blocktree_path) |     let (blocktree, ledger_signal_receiver, completed_slots_receiver) = | ||||||
|         .expect("Expected to successfully open database ledger"); |         Blocktree::open_with_signal(blocktree_path) | ||||||
|  |             .expect("Expected to successfully open database ledger"); | ||||||
|  |  | ||||||
|     let (bank_forks, bank_forks_info, leader_schedule_cache) = |     let (bank_forks, bank_forks_info, leader_schedule_cache) = | ||||||
|         blocktree_processor::process_blocktree(&genesis_block, &blocktree, account_paths) |         blocktree_processor::process_blocktree(&genesis_block, &blocktree, account_paths) | ||||||
| @@ -307,6 +316,7 @@ pub fn new_banks_from_blocktree( | |||||||
|         bank_forks_info, |         bank_forks_info, | ||||||
|         blocktree, |         blocktree, | ||||||
|         ledger_signal_receiver, |         ledger_signal_receiver, | ||||||
|  |         completed_slots_receiver, | ||||||
|         leader_schedule_cache, |         leader_schedule_cache, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| //! regularly finds missing blobs in the ledger and sends repair requests for those blobs | //! regularly finds missing blobs in the ledger and sends repair requests for those blobs | ||||||
|  |  | ||||||
| use crate::bank_forks::BankForks; | use crate::bank_forks::BankForks; | ||||||
| use crate::blocktree::{Blocktree, SlotMeta}; | use crate::blocktree::{Blocktree, CompletedSlotsReceiver, SlotMeta}; | ||||||
| use crate::cluster_info::ClusterInfo; | use crate::cluster_info::ClusterInfo; | ||||||
| use crate::result::Result; | use crate::result::Result; | ||||||
| use crate::service::Service; | use crate::service::Service; | ||||||
| @@ -22,6 +22,14 @@ pub const MAX_REPAIR_TRIES: u64 = 128; | |||||||
| pub const NUM_FORKS_TO_REPAIR: usize = 5; | pub const NUM_FORKS_TO_REPAIR: usize = 5; | ||||||
| pub const MAX_ORPHANS: usize = 5; | pub const MAX_ORPHANS: usize = 5; | ||||||
|  |  | ||||||
|  | pub enum RepairStrategy { | ||||||
|  |     RepairRange(RepairSlotRange), | ||||||
|  |     RepairAll { | ||||||
|  |         bank_forks: Arc<RwLock<BankForks>>, | ||||||
|  |         completed_slots_receiver: CompletedSlotsReceiver, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] | ||||||
| pub enum RepairType { | pub enum RepairType { | ||||||
|     Orphan(u64), |     Orphan(u64), | ||||||
| @@ -68,8 +76,7 @@ impl RepairService { | |||||||
|         exit: &Arc<AtomicBool>, |         exit: &Arc<AtomicBool>, | ||||||
|         repair_socket: Arc<UdpSocket>, |         repair_socket: Arc<UdpSocket>, | ||||||
|         cluster_info: Arc<RwLock<ClusterInfo>>, |         cluster_info: Arc<RwLock<ClusterInfo>>, | ||||||
|         bank_forks: Option<Arc<RwLock<BankForks>>>, |         repair_strategy: RepairStrategy, | ||||||
|         repair_slot_range: Option<RepairSlotRange>, |  | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         let exit = exit.clone(); |         let exit = exit.clone(); | ||||||
|         let t_repair = Builder::new() |         let t_repair = Builder::new() | ||||||
| @@ -80,8 +87,7 @@ impl RepairService { | |||||||
|                     exit, |                     exit, | ||||||
|                     &repair_socket, |                     &repair_socket, | ||||||
|                     &cluster_info, |                     &cluster_info, | ||||||
|                     &bank_forks, |                     repair_strategy, | ||||||
|                     repair_slot_range, |  | ||||||
|                 ) |                 ) | ||||||
|             }) |             }) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
| @@ -94,8 +100,7 @@ impl RepairService { | |||||||
|         exit: Arc<AtomicBool>, |         exit: Arc<AtomicBool>, | ||||||
|         repair_socket: &Arc<UdpSocket>, |         repair_socket: &Arc<UdpSocket>, | ||||||
|         cluster_info: &Arc<RwLock<ClusterInfo>>, |         cluster_info: &Arc<RwLock<ClusterInfo>>, | ||||||
|         bank_forks: &Option<Arc<RwLock<BankForks>>>, |         repair_strategy: RepairStrategy, | ||||||
|         repair_slot_range: Option<RepairSlotRange>, |  | ||||||
|     ) { |     ) { | ||||||
|         let mut repair_info = RepairInfo::new(); |         let mut repair_info = RepairInfo::new(); | ||||||
|         let epoch_slots: HashSet<u64> = HashSet::new(); |         let epoch_slots: HashSet<u64> = HashSet::new(); | ||||||
| @@ -106,20 +111,30 @@ impl RepairService { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             let repairs = { |             let repairs = { | ||||||
|                 if let Some(ref repair_slot_range) = repair_slot_range { |                 match repair_strategy { | ||||||
|                     // Strategy used by replicators |                     RepairStrategy::RepairRange(ref repair_slot_range) => { | ||||||
|                     Self::generate_repairs_in_range( |                         // Strategy used by replicators | ||||||
|                         blocktree, |                         Self::generate_repairs_in_range( | ||||||
|                         MAX_REPAIR_LENGTH, |                             blocktree, | ||||||
|                         &mut repair_info, |                             MAX_REPAIR_LENGTH, | ||||||
|                         repair_slot_range, |                             &mut repair_info, | ||||||
|                     ) |                             repair_slot_range, | ||||||
|                 } else { |                         ) | ||||||
|                     let bank_forks = bank_forks |                     } | ||||||
|                         .as_ref() |  | ||||||
|                         .expect("Non-replicator repair strategy missing BankForks"); |                     RepairStrategy::RepairAll { | ||||||
|                     Self::update_fast_repair(id, &epoch_slots, &cluster_info, bank_forks); |                         ref bank_forks, | ||||||
|                     Self::generate_repairs(blocktree, MAX_REPAIR_LENGTH) |                         ref completed_slots_receiver, | ||||||
|  |                     } => { | ||||||
|  |                         Self::update_epoch_slots( | ||||||
|  |                             id, | ||||||
|  |                             &epoch_slots, | ||||||
|  |                             &cluster_info, | ||||||
|  |                             bank_forks, | ||||||
|  |                             completed_slots_receiver, | ||||||
|  |                         ); | ||||||
|  |                         Self::generate_repairs(blocktree, MAX_REPAIR_LENGTH) | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
| @@ -278,11 +293,14 @@ impl RepairService { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn update_fast_repair( |     // Update the gossiped structure used for the "Repairmen" repair protocol. See book | ||||||
|  |     // for details. | ||||||
|  |     fn update_epoch_slots( | ||||||
|         id: Pubkey, |         id: Pubkey, | ||||||
|         slots: &HashSet<u64>, |         slots: &HashSet<u64>, | ||||||
|         cluster_info: &RwLock<ClusterInfo>, |         cluster_info: &RwLock<ClusterInfo>, | ||||||
|         bank_forks: &Arc<RwLock<BankForks>>, |         bank_forks: &Arc<RwLock<BankForks>>, | ||||||
|  |         _completed_slots_receiver: &CompletedSlotsReceiver, | ||||||
|     ) { |     ) { | ||||||
|         let root = bank_forks.read().unwrap().root(); |         let root = bank_forks.read().unwrap().root(); | ||||||
|         cluster_info |         cluster_info | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ use crate::cluster_info::{ClusterInfo, Node, FULLNODE_PORT_RANGE}; | |||||||
| use crate::contact_info::ContactInfo; | use crate::contact_info::ContactInfo; | ||||||
| use crate::gossip_service::GossipService; | use crate::gossip_service::GossipService; | ||||||
| use crate::packet::to_shared_blob; | use crate::packet::to_shared_blob; | ||||||
| use crate::repair_service::RepairSlotRange; | use crate::repair_service::{RepairSlotRange, RepairStrategy}; | ||||||
| use crate::result::Result; | use crate::result::Result; | ||||||
| use crate::service::Service; | use crate::service::Service; | ||||||
| use crate::storage_stage::SLOTS_PER_SEGMENT; | use crate::storage_stage::SLOTS_PER_SEGMENT; | ||||||
| @@ -232,14 +232,13 @@ impl Replicator { | |||||||
|  |  | ||||||
|         let window_service = WindowService::new( |         let window_service = WindowService::new( | ||||||
|             None, //TODO: need a way to validate blobs... https://github.com/solana-labs/solana/issues/3924 |             None, //TODO: need a way to validate blobs... https://github.com/solana-labs/solana/issues/3924 | ||||||
|             None, //TODO: see above ^ |  | ||||||
|             blocktree.clone(), |             blocktree.clone(), | ||||||
|             cluster_info.clone(), |             cluster_info.clone(), | ||||||
|             blob_fetch_receiver, |             blob_fetch_receiver, | ||||||
|             retransmit_sender, |             retransmit_sender, | ||||||
|             repair_socket, |             repair_socket, | ||||||
|             &exit, |             &exit, | ||||||
|             Some(repair_slot_range), |             RepairStrategy::RepairRange(repair_slot_range), | ||||||
|             &Hash::default(), |             &Hash::default(), | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| //! The `retransmit_stage` retransmits blobs between validators | //! The `retransmit_stage` retransmits blobs between validators | ||||||
|  |  | ||||||
| use crate::bank_forks::BankForks; | use crate::bank_forks::BankForks; | ||||||
| use crate::blocktree::Blocktree; | use crate::blocktree::{Blocktree, CompletedSlotsReceiver}; | ||||||
| use crate::cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT}; | use crate::cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT}; | ||||||
| use crate::leader_schedule_cache::LeaderScheduleCache; | use crate::leader_schedule_cache::LeaderScheduleCache; | ||||||
|  | use crate::repair_service::RepairStrategy; | ||||||
| use crate::result::{Error, Result}; | use crate::result::{Error, Result}; | ||||||
| use crate::service::Service; | use crate::service::Service; | ||||||
| use crate::staking_utils; | use crate::staking_utils; | ||||||
| @@ -108,6 +109,7 @@ pub struct RetransmitStage { | |||||||
|  |  | ||||||
| impl RetransmitStage { | impl RetransmitStage { | ||||||
|     #[allow(clippy::new_ret_no_self)] |     #[allow(clippy::new_ret_no_self)] | ||||||
|  |     #[allow(clippy::too_many_arguments)] | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         bank_forks: Arc<RwLock<BankForks>>, |         bank_forks: Arc<RwLock<BankForks>>, | ||||||
|         leader_schedule_cache: &Arc<LeaderScheduleCache>, |         leader_schedule_cache: &Arc<LeaderScheduleCache>, | ||||||
| @@ -118,6 +120,7 @@ impl RetransmitStage { | |||||||
|         fetch_stage_receiver: BlobReceiver, |         fetch_stage_receiver: BlobReceiver, | ||||||
|         exit: &Arc<AtomicBool>, |         exit: &Arc<AtomicBool>, | ||||||
|         genesis_blockhash: &Hash, |         genesis_blockhash: &Hash, | ||||||
|  |         completed_slots_receiver: CompletedSlotsReceiver, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         let (retransmit_sender, retransmit_receiver) = channel(); |         let (retransmit_sender, retransmit_receiver) = channel(); | ||||||
|  |  | ||||||
| @@ -128,8 +131,12 @@ impl RetransmitStage { | |||||||
|             cluster_info.clone(), |             cluster_info.clone(), | ||||||
|             retransmit_receiver, |             retransmit_receiver, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|  |         let repair_strategy = RepairStrategy::RepairAll { | ||||||
|  |             bank_forks, | ||||||
|  |             completed_slots_receiver, | ||||||
|  |         }; | ||||||
|         let window_service = WindowService::new( |         let window_service = WindowService::new( | ||||||
|             Some(bank_forks), |  | ||||||
|             Some(leader_schedule_cache.clone()), |             Some(leader_schedule_cache.clone()), | ||||||
|             blocktree, |             blocktree, | ||||||
|             cluster_info.clone(), |             cluster_info.clone(), | ||||||
| @@ -137,7 +144,7 @@ impl RetransmitStage { | |||||||
|             retransmit_sender, |             retransmit_sender, | ||||||
|             repair_socket, |             repair_socket, | ||||||
|             exit, |             exit, | ||||||
|             None, |             repair_strategy, | ||||||
|             genesis_blockhash, |             genesis_blockhash, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ | |||||||
| use crate::bank_forks::BankForks; | use crate::bank_forks::BankForks; | ||||||
| use crate::blob_fetch_stage::BlobFetchStage; | use crate::blob_fetch_stage::BlobFetchStage; | ||||||
| use crate::blockstream_service::BlockstreamService; | use crate::blockstream_service::BlockstreamService; | ||||||
| use crate::blocktree::Blocktree; | use crate::blocktree::{Blocktree, CompletedSlotsReceiver}; | ||||||
| use crate::cluster_info::ClusterInfo; | use crate::cluster_info::ClusterInfo; | ||||||
| use crate::leader_schedule_cache::LeaderScheduleCache; | use crate::leader_schedule_cache::LeaderScheduleCache; | ||||||
| use crate::poh_recorder::PohRecorder; | use crate::poh_recorder::PohRecorder; | ||||||
| @@ -71,6 +71,7 @@ impl Tvu { | |||||||
|         leader_schedule_cache: &Arc<LeaderScheduleCache>, |         leader_schedule_cache: &Arc<LeaderScheduleCache>, | ||||||
|         exit: &Arc<AtomicBool>, |         exit: &Arc<AtomicBool>, | ||||||
|         genesis_blockhash: &Hash, |         genesis_blockhash: &Hash, | ||||||
|  |         completed_slots_receiver: CompletedSlotsReceiver, | ||||||
|     ) -> Self |     ) -> Self | ||||||
|     where |     where | ||||||
|         T: 'static + KeypairUtil + Sync + Send, |         T: 'static + KeypairUtil + Sync + Send, | ||||||
| @@ -108,6 +109,7 @@ impl Tvu { | |||||||
|             blob_fetch_receiver, |             blob_fetch_receiver, | ||||||
|             &exit, |             &exit, | ||||||
|             genesis_blockhash, |             genesis_blockhash, | ||||||
|  |             completed_slots_receiver, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         let (replay_stage, slot_full_receiver, root_slot_receiver) = ReplayStage::new( |         let (replay_stage, slot_full_receiver, root_slot_receiver) = ReplayStage::new( | ||||||
| @@ -203,8 +205,9 @@ pub mod tests { | |||||||
|         let cref1 = Arc::new(RwLock::new(cluster_info1)); |         let cref1 = Arc::new(RwLock::new(cluster_info1)); | ||||||
|  |  | ||||||
|         let blocktree_path = get_tmp_ledger_path!(); |         let blocktree_path = get_tmp_ledger_path!(); | ||||||
|         let (blocktree, l_receiver) = Blocktree::open_with_signal(&blocktree_path) |         let (blocktree, l_receiver, completed_slots_receiver) = | ||||||
|             .expect("Expected to successfully open ledger"); |             Blocktree::open_with_signal(&blocktree_path) | ||||||
|  |                 .expect("Expected to successfully open ledger"); | ||||||
|         let blocktree = Arc::new(blocktree); |         let blocktree = Arc::new(blocktree); | ||||||
|         let bank = bank_forks.working_bank(); |         let bank = bank_forks.working_bank(); | ||||||
|         let (exit, poh_recorder, poh_service, _entry_receiver) = |         let (exit, poh_recorder, poh_service, _entry_receiver) = | ||||||
| @@ -233,6 +236,7 @@ pub mod tests { | |||||||
|             &leader_schedule_cache, |             &leader_schedule_cache, | ||||||
|             &exit, |             &exit, | ||||||
|             &Hash::default(), |             &Hash::default(), | ||||||
|  |             completed_slots_receiver, | ||||||
|         ); |         ); | ||||||
|         exit.store(true, Ordering::Relaxed); |         exit.store(true, Ordering::Relaxed); | ||||||
|         tvu.join().unwrap(); |         tvu.join().unwrap(); | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ use crate::cluster_info::ClusterInfo; | |||||||
| use crate::leader_schedule_cache::LeaderScheduleCache; | use crate::leader_schedule_cache::LeaderScheduleCache; | ||||||
| use crate::leader_schedule_utils::slot_leader_at; | use crate::leader_schedule_utils::slot_leader_at; | ||||||
| use crate::packet::{Blob, SharedBlob, BLOB_HEADER_SIZE}; | use crate::packet::{Blob, SharedBlob, BLOB_HEADER_SIZE}; | ||||||
| use crate::repair_service::{RepairService, RepairSlotRange}; | use crate::repair_service::{RepairService, RepairStrategy}; | ||||||
| use crate::result::{Error, Result}; | use crate::result::{Error, Result}; | ||||||
| use crate::service::Service; | use crate::service::Service; | ||||||
| use crate::streamer::{BlobReceiver, BlobSender}; | use crate::streamer::{BlobReceiver, BlobSender}; | ||||||
| @@ -175,7 +175,6 @@ pub struct WindowService { | |||||||
| impl WindowService { | impl WindowService { | ||||||
|     #[allow(clippy::too_many_arguments)] |     #[allow(clippy::too_many_arguments)] | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         bank_forks: Option<Arc<RwLock<BankForks>>>, |  | ||||||
|         leader_schedule_cache: Option<Arc<LeaderScheduleCache>>, |         leader_schedule_cache: Option<Arc<LeaderScheduleCache>>, | ||||||
|         blocktree: Arc<Blocktree>, |         blocktree: Arc<Blocktree>, | ||||||
|         cluster_info: Arc<RwLock<ClusterInfo>>, |         cluster_info: Arc<RwLock<ClusterInfo>>, | ||||||
| @@ -183,16 +182,21 @@ impl WindowService { | |||||||
|         retransmit: BlobSender, |         retransmit: BlobSender, | ||||||
|         repair_socket: Arc<UdpSocket>, |         repair_socket: Arc<UdpSocket>, | ||||||
|         exit: &Arc<AtomicBool>, |         exit: &Arc<AtomicBool>, | ||||||
|         repair_slot_range: Option<RepairSlotRange>, |         repair_strategy: RepairStrategy, | ||||||
|         genesis_blockhash: &Hash, |         genesis_blockhash: &Hash, | ||||||
|     ) -> WindowService { |     ) -> WindowService { | ||||||
|  |         let bank_forks = match repair_strategy { | ||||||
|  |             RepairStrategy::RepairRange(_) => None, | ||||||
|  |  | ||||||
|  |             RepairStrategy::RepairAll { ref bank_forks, .. } => Some(bank_forks.clone()), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|         let repair_service = RepairService::new( |         let repair_service = RepairService::new( | ||||||
|             blocktree.clone(), |             blocktree.clone(), | ||||||
|             exit, |             exit, | ||||||
|             repair_socket, |             repair_socket, | ||||||
|             cluster_info.clone(), |             cluster_info.clone(), | ||||||
|             bank_forks.clone(), |             repair_strategy, | ||||||
|             repair_slot_range, |  | ||||||
|         ); |         ); | ||||||
|         let exit = exit.clone(); |         let exit = exit.clone(); | ||||||
|         let leader_schedule_cache = leader_schedule_cache.clone(); |         let leader_schedule_cache = leader_schedule_cache.clone(); | ||||||
| @@ -207,6 +211,7 @@ impl WindowService { | |||||||
|                     if exit.load(Ordering::Relaxed) { |                     if exit.load(Ordering::Relaxed) { | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if let Err(e) = recv_window( |                     if let Err(e) = recv_window( | ||||||
|                         bank_forks.as_ref(), |                         bank_forks.as_ref(), | ||||||
|                         leader_schedule_cache.as_ref(), |                         leader_schedule_cache.as_ref(), | ||||||
| @@ -351,15 +356,18 @@ mod test { | |||||||
|         let t_receiver = blob_receiver(Arc::new(leader_node.sockets.gossip), &exit, s_reader); |         let t_receiver = blob_receiver(Arc::new(leader_node.sockets.gossip), &exit, s_reader); | ||||||
|         let (s_retransmit, r_retransmit) = channel(); |         let (s_retransmit, r_retransmit) = channel(); | ||||||
|         let blocktree_path = get_tmp_ledger_path!(); |         let blocktree_path = get_tmp_ledger_path!(); | ||||||
|         let blocktree = Arc::new( |         let (blocktree, _, completed_slots_receiver) = Blocktree::open_with_signal(&blocktree_path) | ||||||
|             Blocktree::open(&blocktree_path).expect("Expected to be able to open database ledger"), |             .expect("Expected to be able to open database ledger"); | ||||||
|         ); |         let blocktree = Arc::new(blocktree); | ||||||
|  |  | ||||||
|         let bank = Bank::new(&create_genesis_block_with_leader(100, &me_id, 10).0); |         let bank = Bank::new(&create_genesis_block_with_leader(100, &me_id, 10).0); | ||||||
|         let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); |         let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); | ||||||
|         let bank_forks = Some(Arc::new(RwLock::new(BankForks::new(0, bank)))); |         let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank))); | ||||||
|         let t_window = WindowService::new( |         let repair_strategy = RepairStrategy::RepairAll { | ||||||
|             bank_forks, |             bank_forks, | ||||||
|  |             completed_slots_receiver, | ||||||
|  |         }; | ||||||
|  |         let t_window = WindowService::new( | ||||||
|             Some(leader_schedule_cache), |             Some(leader_schedule_cache), | ||||||
|             blocktree, |             blocktree, | ||||||
|             subs, |             subs, | ||||||
| @@ -367,7 +375,7 @@ mod test { | |||||||
|             s_retransmit, |             s_retransmit, | ||||||
|             Arc::new(leader_node.sockets.repair), |             Arc::new(leader_node.sockets.repair), | ||||||
|             &exit, |             &exit, | ||||||
|             None, |             repair_strategy, | ||||||
|             &Hash::default(), |             &Hash::default(), | ||||||
|         ); |         ); | ||||||
|         let t_responder = { |         let t_responder = { | ||||||
| @@ -430,14 +438,18 @@ mod test { | |||||||
|         let t_receiver = blob_receiver(Arc::new(leader_node.sockets.gossip), &exit, s_reader); |         let t_receiver = blob_receiver(Arc::new(leader_node.sockets.gossip), &exit, s_reader); | ||||||
|         let (s_retransmit, r_retransmit) = channel(); |         let (s_retransmit, r_retransmit) = channel(); | ||||||
|         let blocktree_path = get_tmp_ledger_path!(); |         let blocktree_path = get_tmp_ledger_path!(); | ||||||
|         let blocktree = Arc::new( |         let (blocktree, _, completed_slots_receiver) = Blocktree::open_with_signal(&blocktree_path) | ||||||
|             Blocktree::open(&blocktree_path).expect("Expected to be able to open database ledger"), |             .expect("Expected to be able to open database ledger"); | ||||||
|         ); |  | ||||||
|  |         let blocktree = Arc::new(blocktree); | ||||||
|         let bank = Bank::new(&create_genesis_block_with_leader(100, &me_id, 10).0); |         let bank = Bank::new(&create_genesis_block_with_leader(100, &me_id, 10).0); | ||||||
|         let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); |         let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank)); | ||||||
|         let bank_forks = Some(Arc::new(RwLock::new(BankForks::new(0, bank)))); |         let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank))); | ||||||
|         let t_window = WindowService::new( |         let repair_strategy = RepairStrategy::RepairAll { | ||||||
|             bank_forks, |             bank_forks, | ||||||
|  |             completed_slots_receiver, | ||||||
|  |         }; | ||||||
|  |         let t_window = WindowService::new( | ||||||
|             Some(leader_schedule_cache), |             Some(leader_schedule_cache), | ||||||
|             blocktree, |             blocktree, | ||||||
|             subs.clone(), |             subs.clone(), | ||||||
| @@ -445,7 +457,7 @@ mod test { | |||||||
|             s_retransmit, |             s_retransmit, | ||||||
|             Arc::new(leader_node.sockets.repair), |             Arc::new(leader_node.sockets.repair), | ||||||
|             &exit, |             &exit, | ||||||
|             None, |             repair_strategy, | ||||||
|             &Hash::default(), |             &Hash::default(), | ||||||
|         ); |         ); | ||||||
|         let t_responder = { |         let t_responder = { | ||||||
|   | |||||||
| @@ -83,8 +83,14 @@ fn test_replay() { | |||||||
|  |  | ||||||
|     let tvu_addr = target1.info.tvu; |     let tvu_addr = target1.info.tvu; | ||||||
|  |  | ||||||
|     let (bank_forks, _bank_forks_info, blocktree, ledger_signal_receiver, leader_schedule_cache) = |     let ( | ||||||
|         fullnode::new_banks_from_blocktree(&blocktree_path, None); |         bank_forks, | ||||||
|  |         _bank_forks_info, | ||||||
|  |         blocktree, | ||||||
|  |         ledger_signal_receiver, | ||||||
|  |         completed_slots_receiver, | ||||||
|  |         leader_schedule_cache, | ||||||
|  |     ) = fullnode::new_banks_from_blocktree(&blocktree_path, None); | ||||||
|     let working_bank = bank_forks.working_bank(); |     let working_bank = bank_forks.working_bank(); | ||||||
|     assert_eq!( |     assert_eq!( | ||||||
|         working_bank.get_balance(&mint_keypair.pubkey()), |         working_bank.get_balance(&mint_keypair.pubkey()), | ||||||
| @@ -126,6 +132,7 @@ fn test_replay() { | |||||||
|             &leader_schedule_cache, |             &leader_schedule_cache, | ||||||
|             &exit, |             &exit, | ||||||
|             &solana_sdk::hash::Hash::default(), |             &solana_sdk::hash::Hash::default(), | ||||||
|  |             completed_slots_receiver, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         let mut mint_ref_balance = mint_balance; |         let mut mint_ref_balance = mint_balance; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user