slot_store.rs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. // [`Slot`] is defined in the sdk so contracts can use it
  19. use darkfi_sdk::blockchain::Slot;
  20. use darkfi_serial::{deserialize, serialize};
  21. use crate::{Error, Result};
  22. use super::{parse_record, SledDbOverlayPtr};
  23. const SLED_SLOT_TREE: &[u8] = b"_slots";
  24. /// The `SlotStore` is a `sled` tree storing the blockhains' slots,
  25. /// where the key is the slot uid, and the value is is the serialized slot.
  26. #[derive(Clone)]
  27. pub struct SlotStore(pub sled::Tree);
  28. impl SlotStore {
  29. /// Opens a new or existing `SlotStore` on the given sled database.
  30. pub fn new(db: &sled::Db) -> Result<Self> {
  31. let tree = db.open_tree(SLED_SLOT_TREE)?;
  32. Ok(Self(tree))
  33. }
  34. /// Insert a slice of [`Slot`] into the slot store.
  35. pub fn insert(&self, slots: &[Slot]) -> Result<()> {
  36. let batch = self.insert_batch(slots)?;
  37. self.0.apply_batch(batch)?;
  38. Ok(())
  39. }
  40. /// Generate the sled batch corresponding to an insert, so caller
  41. /// can handle the write operation.
  42. /// The slot id is used as the key, while value is the serialized [`Slot`] itself.
  43. pub fn insert_batch(&self, slots: &[Slot]) -> Result<sled::Batch> {
  44. let mut batch = sled::Batch::default();
  45. for slot in slots {
  46. let serialized = serialize(slot);
  47. batch.insert(&slot.id.to_be_bytes(), serialized);
  48. }
  49. Ok(batch)
  50. }
  51. /// Check if the slot store contains a given id.
  52. pub fn contains(&self, id: u64) -> Result<bool> {
  53. Ok(self.0.contains_key(id.to_be_bytes())?)
  54. }
  55. /// Fetch given slots from the slot store.
  56. /// The resulting vector contains `Option`, which is `Some` if the slot
  57. /// was found in the slot store, and otherwise it is `None`, if it has not.
  58. /// The second parameter is a boolean which tells the function to fail in
  59. /// case at least one slot was not found.
  60. pub fn get(&self, ids: &[u64], strict: bool) -> Result<Vec<Option<Slot>>> {
  61. let mut ret = Vec::with_capacity(ids.len());
  62. for id in ids {
  63. if let Some(found) = self.0.get(id.to_be_bytes())? {
  64. let slot = deserialize(&found)?;
  65. ret.push(Some(slot));
  66. } else {
  67. if strict {
  68. return Err(Error::SlotNotFound(*id))
  69. }
  70. ret.push(None);
  71. }
  72. }
  73. Ok(ret)
  74. }
  75. /// Retrieve all slot from the slot store.
  76. /// Be careful as this will try to load everything in memory.
  77. pub fn get_all(&self) -> Result<Vec<Slot>> {
  78. let mut slots = vec![];
  79. for slot in self.0.iter() {
  80. let (_, slot): ([u8; 8], Slot) = parse_record(slot.unwrap())?;
  81. slots.push(slot);
  82. }
  83. Ok(slots)
  84. }
  85. /// Fetch n slots after given slot. In the iteration, if a slot is not
  86. /// found, the iteration stops and the function returns what it has found
  87. /// so far in the `SlotStore`.
  88. pub fn get_after(&self, id: u64, n: u64) -> Result<Vec<Slot>> {
  89. let mut ret = vec![];
  90. let mut key = id;
  91. let mut counter = 0;
  92. while counter <= n {
  93. if let Some(found) = self.0.get_gt(key.to_be_bytes())? {
  94. let (id, slot) = parse_record(found)?;
  95. key = id;
  96. ret.push(slot);
  97. counter += 1;
  98. continue
  99. }
  100. break
  101. }
  102. Ok(ret)
  103. }
  104. /// Fetch the last slot in the tree, based on the `Ord`
  105. /// implementation for `Vec<u8>`. This should not be able to
  106. /// fail because we initialize the store with the genesis slot.
  107. pub fn get_last(&self) -> Result<Slot> {
  108. let found = self.0.last()?.unwrap();
  109. let slot = deserialize(&found.1)?;
  110. Ok(slot)
  111. }
  112. /// Retrieve records count
  113. pub fn len(&self) -> usize {
  114. self.0.len()
  115. }
  116. pub fn is_empty(&self) -> bool {
  117. self.0.is_empty()
  118. }
  119. }
  120. /// Overlay structure over a [`SlotStore`] instance.
  121. pub struct SlotStoreOverlay(SledDbOverlayPtr);
  122. impl SlotStoreOverlay {
  123. pub fn new(overlay: SledDbOverlayPtr) -> Result<Self> {
  124. overlay.lock().unwrap().open_tree(SLED_SLOT_TREE)?;
  125. Ok(Self(overlay))
  126. }
  127. /// Insert a slice of [`Slot`] into the overlay.
  128. /// The slot id is used as the key, while value is the serialized [`Slot`] itself.
  129. pub fn insert(&self, slots: &[Slot]) -> Result<()> {
  130. let mut lock = self.0.lock().unwrap();
  131. for slot in slots {
  132. let serialized = serialize(slot);
  133. lock.insert(SLED_SLOT_TREE, &slot.id.to_be_bytes(), &serialized)?;
  134. }
  135. Ok(())
  136. }
  137. /// Fetch slot from the overlay by id.
  138. pub fn get_by_id(&self, id: u64) -> Result<Vec<u8>> {
  139. match self.0.lock().unwrap().get(SLED_SLOT_TREE, &id.to_be_bytes())? {
  140. Some(found) => Ok(found.to_vec()),
  141. None => Err(Error::SlotNotFound(id)),
  142. }
  143. }
  144. /// Fetch given slots from the overlay.
  145. /// The resulting vector contains `Option`, which is `Some` if the slot
  146. /// was found in the overlay, and otherwise it is `None`, if it has not.
  147. /// The second parameter is a boolean which tells the function to fail in
  148. /// case at least one slot was not found.
  149. pub fn get(&self, ids: &[u64], strict: bool) -> Result<Vec<Option<Slot>>> {
  150. let mut ret = Vec::with_capacity(ids.len());
  151. let lock = self.0.lock().unwrap();
  152. for id in ids {
  153. if let Some(found) = lock.get(SLED_SLOT_TREE, &id.to_be_bytes())? {
  154. let slot = deserialize(&found)?;
  155. ret.push(Some(slot));
  156. } else {
  157. if strict {
  158. return Err(Error::SlotNotFound(*id))
  159. }
  160. ret.push(None);
  161. }
  162. }
  163. Ok(ret)
  164. }
  165. }