/ ledger / store / src / program / committee.rs
committee.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use crate::{
 17      atomic_batch_scope,
 18      helpers::{Map, MapRead},
 19  };
 20  use deltavm_ledger_committee::Committee;
 21  use console::network::prelude::*;
 22  
 23  use alphastd_storage::StorageMode;
 24  use anyhow::Result;
 25  use core::marker::PhantomData;
 26  
 27  const ROUND_KEY: u8 = 0;
 28  
 29  /// A trait for committee storage.
 30  pub trait CommitteeStorage<N: Network>: 'static + Clone + Send + Sync {
 31      /// The mapping of `()` to `current round`.
 32      type CurrentRoundMap: for<'a> Map<'a, u8, u64>;
 33      /// The mapping of `round` to `height`.
 34      type RoundToHeightMap: for<'a> Map<'a, u64, u32>;
 35      /// The mapping of `block height` to `committee`.
 36      type CommitteeMap: for<'a> Map<'a, u32, Committee<N>>;
 37  
 38      /// Initializes the committee storage.
 39      fn open<S: Into<StorageMode>>(storage: S) -> Result<Self>;
 40  
 41      /// Returns the current round map.
 42      fn current_round_map(&self) -> &Self::CurrentRoundMap;
 43      /// Returns the round to height map.
 44      fn round_to_height_map(&self) -> &Self::RoundToHeightMap;
 45      /// Returns the committee map.
 46      fn committee_map(&self) -> &Self::CommitteeMap;
 47  
 48      /// Returns the storage mode.
 49      fn storage_mode(&self) -> &StorageMode;
 50  
 51      /// Starts an atomic batch write operation.
 52      fn start_atomic(&self) {
 53          self.current_round_map().start_atomic();
 54          self.round_to_height_map().start_atomic();
 55          self.committee_map().start_atomic();
 56      }
 57  
 58      /// Checks if an atomic batch is in progress.
 59      fn is_atomic_in_progress(&self) -> bool {
 60          self.current_round_map().is_atomic_in_progress()
 61              || self.round_to_height_map().is_atomic_in_progress()
 62              || self.committee_map().is_atomic_in_progress()
 63      }
 64  
 65      /// Checkpoints the atomic batch.
 66      fn atomic_checkpoint(&self) {
 67          self.current_round_map().atomic_checkpoint();
 68          self.round_to_height_map().atomic_checkpoint();
 69          self.committee_map().atomic_checkpoint();
 70      }
 71  
 72      /// Clears the latest atomic batch checkpoint.
 73      fn clear_latest_checkpoint(&self) {
 74          self.current_round_map().clear_latest_checkpoint();
 75          self.round_to_height_map().clear_latest_checkpoint();
 76          self.committee_map().clear_latest_checkpoint();
 77      }
 78  
 79      /// Rewinds the atomic batch to the previous checkpoint.
 80      fn atomic_rewind(&self) {
 81          self.current_round_map().atomic_rewind();
 82          self.round_to_height_map().atomic_rewind();
 83          self.committee_map().atomic_rewind();
 84      }
 85  
 86      /// Aborts an atomic batch write operation.
 87      fn abort_atomic(&self) {
 88          self.current_round_map().abort_atomic();
 89          self.round_to_height_map().abort_atomic();
 90          self.committee_map().abort_atomic();
 91      }
 92  
 93      /// Finishes an atomic batch write operation.
 94      fn finish_atomic(&self) -> Result<()> {
 95          self.current_round_map().finish_atomic()?;
 96          self.round_to_height_map().finish_atomic()?;
 97          self.committee_map().finish_atomic()
 98      }
 99  
100      /// Stores the given `(next height, committee)` pair into storage,
101      /// and indexes storage up to the `next round`.
102      fn insert(&self, next_height: u32, committee: Committee<N>) -> Result<()> {
103          // Retrieve the next round.
104          let next_round = committee.starting_round();
105          // Ensure the next round is at least the next height.
106          ensure!(next_round >= next_height as u64, "Next round must be at least the next height");
107  
108          // Check the next round.
109          match self.current_round() {
110              // If the current round is 0, ensure the next round is 0.
111              Err(..) => ensure!(next_round == 0, "Next round must be block round 0"),
112              // Otherwise, ensure the next round sequentially follows the current round.
113              Ok(current_round) => ensure!(
114                  next_round > current_round,
115                  "Next round {next_round} must be greater than current round {current_round}"
116              ),
117          }
118  
119          // Check the next height.
120          match self.current_height() {
121              // If the current height is 0, ensure the next height is 0.
122              Err(..) => ensure!(next_height == 0, "Next height must be block height 0"),
123              // Otherwise, ensure the next height sequentially follows the current height.
124              Ok(current_height) => ensure!(next_height == current_height + 1, "Next height must be sequential"),
125          }
126  
127          // If the next round already exists, then return an error.
128          ensure!(
129              !self.round_to_height_map().contains_key_confirmed(&next_round)?,
130              "Next round {next_round} already exists in committee storage"
131          );
132  
133          // Determine the catch up round.
134          let catch_up_round = match self.current_round() {
135              Err(..) => 0,
136              Ok(current_round) => current_round + 1,
137          };
138  
139          // Start an atomic batch.
140          atomic_batch_scope!(self, {
141              // Store the next round.
142              self.current_round_map().insert(ROUND_KEY, next_round)?;
143  
144              // If the current height exists, then store missing rounds up to the *next* height.
145              if let Ok(current_height) = self.current_height() {
146                  // Store the round to height mappings.
147                  for round in catch_up_round..next_round {
148                      // Note: We store the 'current_height' as the *next* round starts the *next* height.
149                      self.round_to_height_map().insert(round, current_height)?;
150                  }
151              }
152              // Store the next round's height.
153              self.round_to_height_map().insert(next_round, next_height)?;
154  
155              // Store the committee.
156              self.committee_map().insert(next_height, committee)?;
157              Ok(())
158          })
159      }
160  
161      /// Removes the committee for the given `height`, in the process
162      /// removing all round to height entries back to the previous committee.
163      fn remove(&self, height: u32) -> Result<()> {
164          // Retrieve the current round.
165          let current_round = self.current_round()?;
166          // Retrieve the current height.
167          let current_height = self.current_height()?;
168          // Retrieve the committee for the given height.
169          let Some(committee) = self.get_committee(height)? else {
170              bail!("Committee not found for height {height} in committee storage");
171          };
172          // Retrieve the round for the given height.
173          let committee_round = committee.starting_round();
174  
175          // If the current height matches the given height, it means we are removing the latest committee,
176          // and we will need to update the current round.
177          let is_latest_committee = current_height == height;
178  
179          // Find the earliest round to be removed (inclusive).
180          let mut earliest_round = committee_round;
181          while earliest_round > 0 && self.get_height_for_round(earliest_round)? == Some(height) {
182              earliest_round = earliest_round.saturating_sub(1);
183          }
184          let is_multiple = earliest_round != committee_round;
185          if is_multiple {
186              earliest_round += 1;
187          }
188  
189          // Find the latest round to be removed (exclusive).
190          let mut latest_round = committee_round;
191          while self.get_height_for_round(latest_round)? == Some(height) {
192              latest_round = latest_round.saturating_add(1);
193          }
194  
195          // If we are removing the latest committee, determine the next current round.
196          let mut next_current_round = current_round.saturating_sub(1);
197          if is_latest_committee {
198              while next_current_round > 0 {
199                  // If the next current height is less than the current height, then we have found the next current round.
200                  if let Some(next_current_height) = self.get_height_for_round(next_current_round)? {
201                      if next_current_height < current_height {
202                          break;
203                      }
204                  }
205                  // Otherwise, decrement the next current round.
206                  next_current_round = next_current_round.saturating_sub(1);
207              }
208          }
209  
210          // Start an atomic batch.
211          atomic_batch_scope!(self, {
212              // Update the current round, if this is the latest round.
213              if is_latest_committee {
214                  // Remove the current round.
215                  self.current_round_map().remove(&ROUND_KEY)?;
216                  // If the next current round is greater than 0, then insert it.
217                  if current_round != next_current_round && next_current_round > 0 {
218                      // Insert the previous round.
219                      self.current_round_map().insert(ROUND_KEY, next_current_round)?;
220                  }
221              }
222              // Remove the round to height mappings.
223              for round in earliest_round..latest_round {
224                  self.round_to_height_map().remove(&round)?;
225              }
226              // Remove the committee.
227              self.committee_map().remove(&height)?;
228  
229              Ok(())
230          })
231      }
232  
233      /// Returns the current round.
234      fn current_round(&self) -> Result<u64> {
235          let Some(round) = self.current_round_map().get_confirmed(&ROUND_KEY)? else {
236              bail!("Current round not found in committee storage");
237          };
238          Ok(*round)
239      }
240  
241      /// Returns the current height.
242      fn current_height(&self) -> Result<u32> {
243          // Retrieve the current round.
244          let current_round = self.current_round()?;
245          // Retrieve the current height.
246          let Some(height) = self.round_to_height_map().get_confirmed(&current_round)? else {
247              bail!("Current height not found in committee storage");
248          };
249          Ok(*height)
250      }
251  
252      /// Returns the current committee.
253      fn current_committee(&self) -> Result<Committee<N>> {
254          self.get_committee(self.current_height()?)?
255              .ok_or_else(|| anyhow!("Current committee not found in committee storage"))
256      }
257  
258      /// Returns the height for the given `round`.
259      fn get_height_for_round(&self, round: u64) -> Result<Option<u32>> {
260          Ok(self.round_to_height_map().get_confirmed(&round)?.map(|x| *x))
261      }
262  
263      /// Returns the committee for the given `height`.
264      fn get_committee(&self, height: u32) -> Result<Option<Committee<N>>> {
265          Ok(self.committee_map().get_confirmed(&height)?.map(|x| x.into_owned()))
266      }
267  
268      /// Returns the committee for the given `round`.
269      fn get_committee_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
270          // Retrieve the height for the given round.
271          match self.get_height_for_round(round)? {
272              // Retrieve the committee for the given height.
273              Some(height) => Ok(self.get_committee(height)?),
274              None => Ok(None),
275          }
276      }
277  }
278  
279  /// The committee store.
280  #[derive(Clone)]
281  pub struct CommitteeStore<N: Network, C: CommitteeStorage<N>> {
282      /// The committee storage.
283      storage: C,
284      /// PhantomData.
285      _phantom: PhantomData<N>,
286  }
287  
288  impl<N: Network, C: CommitteeStorage<N>> CommitteeStore<N, C> {
289      /// Initializes the committee store.
290      pub fn open<S: Into<StorageMode>>(storage: S) -> Result<Self> {
291          // Initialize the committee storage.
292          let storage = C::open(storage)?;
293          // Return the committee store.
294          Ok(Self { storage, _phantom: PhantomData })
295      }
296  
297      /// Initializes a committee store from storage.
298      pub fn from(storage: C) -> Self {
299          Self { storage, _phantom: PhantomData }
300      }
301  
302      /// Starts an atomic batch write operation.
303      pub fn start_atomic(&self) {
304          self.storage.start_atomic();
305      }
306  
307      /// Checks if an atomic batch is in progress.
308      pub fn is_atomic_in_progress(&self) -> bool {
309          self.storage.is_atomic_in_progress()
310      }
311  
312      /// Checkpoints the atomic batch.
313      pub fn atomic_checkpoint(&self) {
314          self.storage.atomic_checkpoint();
315      }
316  
317      /// Clears the latest atomic batch checkpoint.
318      pub fn clear_latest_checkpoint(&self) {
319          self.storage.clear_latest_checkpoint();
320      }
321  
322      /// Rewinds the atomic batch to the previous checkpoint.
323      pub fn atomic_rewind(&self) {
324          self.storage.atomic_rewind();
325      }
326  
327      /// Aborts an atomic batch write operation.
328      pub fn abort_atomic(&self) {
329          self.storage.abort_atomic();
330      }
331  
332      /// Finishes an atomic batch write operation.
333      pub fn finish_atomic(&self) -> Result<()> {
334          self.storage.finish_atomic()
335      }
336  
337      /// Returns the storage mode.
338      pub fn storage_mode(&self) -> &StorageMode {
339          self.storage.storage_mode()
340      }
341  }
342  
343  impl<N: Network, C: CommitteeStorage<N>> CommitteeStore<N, C> {
344      /// Stores the given `(next height, committee)` pair into storage,
345      /// and indexes storage up to the `next round`.
346      pub fn insert(&self, next_height: u32, committee: Committee<N>) -> Result<()> {
347          self.storage.insert(next_height, committee)
348      }
349  
350      /// Removes the committee for the given `height`, in the process
351      /// removing all round to height entries back to the previous committee.
352      pub fn remove(&self, height: u32) -> Result<()> {
353          self.storage.remove(height)
354      }
355  }
356  
357  impl<N: Network, C: CommitteeStorage<N>> CommitteeStore<N, C> {
358      /// Returns the current round.
359      pub fn current_round(&self) -> Result<u64> {
360          self.storage.current_round()
361      }
362  
363      /// Returns the current height.
364      pub fn current_height(&self) -> Result<u32> {
365          self.storage.current_height()
366      }
367  
368      /// Returns the current committee.
369      pub fn current_committee(&self) -> Result<Committee<N>> {
370          self.storage.current_committee()
371      }
372  
373      /// Returns the height for the given `round`.
374      pub fn get_height_for_round(&self, round: u64) -> Result<Option<u32>> {
375          self.storage.get_height_for_round(round)
376      }
377  
378      /// Returns the committee for the given `height`.
379      pub fn get_committee(&self, height: u32) -> Result<Option<Committee<N>>> {
380          self.storage.get_committee(height)
381      }
382  
383      /// Returns the committee for the given `round`.
384      pub fn get_committee_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
385          self.storage.get_committee_for_round(round)
386      }
387  }
388  
389  #[cfg(test)]
390  mod tests {
391      use super::*;
392      use crate::helpers::memory::CommitteeMemory;
393  
394      type CurrentNetwork = console::network::MainnetV0;
395  
396      #[test]
397      fn test_insert_get_remove() {
398          let rng = &mut TestRng::default();
399  
400          // Sample the committee.
401          let committee_0 = deltavm_ledger_committee::test_helpers::sample_committee_for_round(0, rng);
402  
403          // Initialize a new committee store.
404          let store = CommitteeStore::<CurrentNetwork, CommitteeMemory<_>>::open(StorageMode::new_test(None)).unwrap();
405          assert!(store.current_round().is_err());
406          assert!(store.current_height().is_err());
407          assert!(store.current_committee().is_err());
408          assert_eq!(store.get_height_for_round(rng.r#gen()).unwrap(), None);
409          assert_eq!(store.get_committee(rng.r#gen()).unwrap(), None);
410          assert_eq!(store.get_committee_for_round(rng.r#gen()).unwrap(), None);
411  
412          // Insert the committee.
413          store.insert(0, committee_0.clone()).unwrap();
414          assert_eq!(store.current_round().unwrap(), 0);
415          assert_eq!(store.current_height().unwrap(), 0);
416          assert_eq!(store.current_committee().unwrap(), committee_0);
417  
418          assert_eq!(store.get_height_for_round(0).unwrap().unwrap(), 0);
419          assert_eq!(store.get_height_for_round(1).unwrap(), None);
420          assert_eq!(store.get_height_for_round(2).unwrap(), None);
421          assert_eq!(store.get_height_for_round(3).unwrap(), None);
422  
423          assert_eq!(store.get_committee(0).unwrap().unwrap(), committee_0);
424          assert_eq!(store.get_committee(1).unwrap(), None);
425          assert_eq!(store.get_committee(2).unwrap(), None);
426  
427          assert_eq!(store.get_committee_for_round(0).unwrap().unwrap(), committee_0);
428          assert_eq!(store.get_committee_for_round(1).unwrap(), None);
429          assert_eq!(store.get_committee_for_round(2).unwrap(), None);
430          assert_eq!(store.get_committee_for_round(3).unwrap(), None);
431  
432          // Sample another committee.
433          let committee_1 = deltavm_ledger_committee::test_helpers::sample_committee_for_round(5, rng);
434  
435          // Insert the committee.
436          store.insert(1, committee_1.clone()).unwrap();
437          assert_eq!(store.current_round().unwrap(), 5);
438          assert_eq!(store.current_height().unwrap(), 1);
439          assert_eq!(store.current_committee().unwrap(), committee_1);
440  
441          assert_eq!(store.get_height_for_round(0).unwrap().unwrap(), 0);
442          assert_eq!(store.get_height_for_round(1).unwrap().unwrap(), 0);
443          assert_eq!(store.get_height_for_round(2).unwrap().unwrap(), 0);
444          assert_eq!(store.get_height_for_round(3).unwrap().unwrap(), 0);
445          assert_eq!(store.get_height_for_round(4).unwrap().unwrap(), 0);
446          assert_eq!(store.get_height_for_round(5).unwrap().unwrap(), 1);
447          assert_eq!(store.get_height_for_round(6).unwrap(), None);
448  
449          assert_eq!(store.get_committee(0).unwrap().unwrap(), committee_0);
450          assert_eq!(store.get_committee(1).unwrap().unwrap(), committee_1);
451          assert_eq!(store.get_committee(2).unwrap(), None);
452          assert_eq!(store.get_committee(3).unwrap(), None);
453  
454          assert_eq!(store.get_committee_for_round(0).unwrap().unwrap(), committee_0);
455          assert_eq!(store.get_committee_for_round(1).unwrap().unwrap(), committee_0);
456          assert_eq!(store.get_committee_for_round(2).unwrap().unwrap(), committee_0);
457          assert_eq!(store.get_committee_for_round(3).unwrap().unwrap(), committee_0);
458          assert_eq!(store.get_committee_for_round(4).unwrap().unwrap(), committee_0);
459          assert_eq!(store.get_committee_for_round(5).unwrap().unwrap(), committee_1);
460          assert_eq!(store.get_committee_for_round(6).unwrap(), None);
461  
462          // Remove the committee.
463          assert!(store.remove(2).is_err());
464          store.remove(1).unwrap();
465          assert!(store.remove(1).is_err());
466          assert_eq!(store.current_round().unwrap(), 4);
467          assert_eq!(store.current_height().unwrap(), 0);
468          assert_eq!(store.current_committee().unwrap(), committee_0);
469  
470          assert_eq!(store.get_height_for_round(0).unwrap().unwrap(), 0);
471          assert_eq!(store.get_height_for_round(1).unwrap().unwrap(), 0);
472          assert_eq!(store.get_height_for_round(2).unwrap().unwrap(), 0);
473          assert_eq!(store.get_height_for_round(3).unwrap().unwrap(), 0);
474          assert_eq!(store.get_height_for_round(4).unwrap().unwrap(), 0);
475          assert_eq!(store.get_height_for_round(5).unwrap(), None);
476          assert_eq!(store.get_height_for_round(6).unwrap(), None);
477  
478          assert_eq!(store.get_committee(0).unwrap().unwrap(), committee_0);
479          assert_eq!(store.get_committee(1).unwrap(), None);
480          assert_eq!(store.get_committee(2).unwrap(), None);
481          assert_eq!(store.get_committee(3).unwrap(), None);
482  
483          assert_eq!(store.get_committee_for_round(0).unwrap().unwrap(), committee_0);
484          assert_eq!(store.get_committee_for_round(1).unwrap().unwrap(), committee_0);
485          assert_eq!(store.get_committee_for_round(2).unwrap().unwrap(), committee_0);
486          assert_eq!(store.get_committee_for_round(3).unwrap().unwrap(), committee_0);
487          assert_eq!(store.get_committee_for_round(4).unwrap().unwrap(), committee_0);
488          assert_eq!(store.get_committee_for_round(5).unwrap(), None);
489          assert_eq!(store.get_committee_for_round(6).unwrap(), None);
490  
491          // Remove the committee.
492          store.remove(0).unwrap();
493          assert!(store.current_round().is_err());
494          assert!(store.current_height().is_err());
495          assert!(store.current_committee().is_err());
496  
497          assert_eq!(store.get_height_for_round(0).unwrap(), None);
498          assert_eq!(store.get_height_for_round(1).unwrap(), None);
499          assert_eq!(store.get_height_for_round(2).unwrap(), None);
500          assert_eq!(store.get_height_for_round(3).unwrap(), None);
501          assert_eq!(store.get_height_for_round(4).unwrap(), None);
502          assert_eq!(store.get_height_for_round(5).unwrap(), None);
503  
504          assert_eq!(store.get_committee(0).unwrap(), None);
505          assert_eq!(store.get_committee(1).unwrap(), None);
506          assert_eq!(store.get_committee(2).unwrap(), None);
507          assert_eq!(store.get_committee(3).unwrap(), None);
508  
509          assert_eq!(store.get_committee_for_round(0).unwrap(), None);
510          assert_eq!(store.get_committee_for_round(1).unwrap(), None);
511          assert_eq!(store.get_committee_for_round(2).unwrap(), None);
512          assert_eq!(store.get_committee_for_round(3).unwrap(), None);
513          assert_eq!(store.get_committee_for_round(4).unwrap(), None);
514          assert_eq!(store.get_committee_for_round(5).unwrap(), None);
515      }
516  
517      #[test]
518      fn test_remove_hole() {
519          let rng = &mut TestRng::default();
520  
521          // Sample the committee.
522          let committee_0 = deltavm_ledger_committee::test_helpers::sample_committee_for_round(0, rng);
523  
524          // Initialize a new committee store.
525          let store = CommitteeStore::<CurrentNetwork, CommitteeMemory<_>>::open(StorageMode::new_test(None)).unwrap();
526          assert!(store.current_round().is_err());
527          assert!(store.current_height().is_err());
528          assert!(store.current_committee().is_err());
529  
530          // Insert the committee.
531          store.insert(0, committee_0.clone()).unwrap();
532          assert_eq!(store.current_round().unwrap(), 0);
533          assert_eq!(store.current_height().unwrap(), 0);
534          assert_eq!(store.current_committee().unwrap(), committee_0);
535  
536          // Sample another committee.
537          let committee_1 = deltavm_ledger_committee::test_helpers::sample_committee_for_round(5, rng);
538  
539          // Insert the committee.
540          store.insert(1, committee_1.clone()).unwrap();
541          assert_eq!(store.current_round().unwrap(), 5);
542          assert_eq!(store.current_height().unwrap(), 1);
543          assert_eq!(store.current_committee().unwrap(), committee_1);
544  
545          // Observe: We remove the committee for round 2, but the current committee is still the one for round 5.
546  
547          // Remove the committee.
548          store.remove(0).unwrap();
549          assert_eq!(store.current_round().unwrap(), 5);
550          assert_eq!(store.current_height().unwrap(), 1);
551          assert_eq!(store.current_committee().unwrap(), committee_1);
552  
553          assert_eq!(store.get_height_for_round(1).unwrap(), None);
554          assert_eq!(store.get_height_for_round(2).unwrap(), None);
555          assert_eq!(store.get_height_for_round(3).unwrap(), None);
556          assert_eq!(store.get_height_for_round(4).unwrap(), None);
557          assert_eq!(store.get_height_for_round(5).unwrap().unwrap(), 1);
558          assert_eq!(store.get_height_for_round(6).unwrap(), None);
559  
560          assert_eq!(store.get_committee(0).unwrap(), None);
561          assert_eq!(store.get_committee(1).unwrap().unwrap(), committee_1);
562          assert_eq!(store.get_committee(2).unwrap(), None);
563          assert_eq!(store.get_committee(3).unwrap(), None);
564  
565          assert_eq!(store.get_committee_for_round(1).unwrap(), None);
566          assert_eq!(store.get_committee_for_round(2).unwrap(), None);
567          assert_eq!(store.get_committee_for_round(3).unwrap(), None);
568          assert_eq!(store.get_committee_for_round(4).unwrap(), None);
569          assert_eq!(store.get_committee_for_round(5).unwrap().unwrap(), committee_1);
570          assert_eq!(store.get_committee_for_round(6).unwrap(), None);
571  
572          // Remove the committee.
573          store.remove(1).unwrap();
574          assert!(store.current_round().is_err());
575          assert!(store.current_height().is_err());
576          assert!(store.current_committee().is_err());
577  
578          assert_eq!(store.get_height_for_round(1).unwrap(), None);
579          assert_eq!(store.get_height_for_round(2).unwrap(), None);
580          assert_eq!(store.get_height_for_round(3).unwrap(), None);
581          assert_eq!(store.get_height_for_round(4).unwrap(), None);
582          assert_eq!(store.get_height_for_round(5).unwrap(), None);
583  
584          assert_eq!(store.get_committee(0).unwrap(), None);
585          assert_eq!(store.get_committee(1).unwrap(), None);
586          assert_eq!(store.get_committee(2).unwrap(), None);
587          assert_eq!(store.get_committee(3).unwrap(), None);
588  
589          assert_eq!(store.get_committee_for_round(1).unwrap(), None);
590          assert_eq!(store.get_committee_for_round(2).unwrap(), None);
591          assert_eq!(store.get_committee_for_round(3).unwrap(), None);
592          assert_eq!(store.get_committee_for_round(4).unwrap(), None);
593          assert_eq!(store.get_committee_for_round(5).unwrap(), None);
594      }
595  }