tx_store.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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. use std::collections::HashMap;
  19. use darkfi_serial::{deserialize, serialize};
  20. use crate::{tx::Transaction, Error, Result};
  21. use super::SledDbOverlayPtr;
  22. const SLED_TX_TREE: &[u8] = b"_transactions";
  23. const SLED_PENDING_TX_TREE: &[u8] = b"_pending_transactions";
  24. const SLED_PENDING_TX_ORDER_TREE: &[u8] = b"_pending_transactions_order";
  25. /// The `TxStore` is a `sled` tree storing all the blockchain's
  26. /// transactions where the key is the transaction hash, and the value is
  27. /// the serialized transaction.
  28. #[derive(Clone)]
  29. pub struct TxStore(pub sled::Tree);
  30. impl TxStore {
  31. /// Opens a new or existing `TxStore` on the given sled database.
  32. pub fn new(db: &sled::Db) -> Result<Self> {
  33. let tree = db.open_tree(SLED_TX_TREE)?;
  34. Ok(Self(tree))
  35. }
  36. /// Insert a slice of [`Transaction`] into the txstore.
  37. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  38. let (batch, ret) = self.insert_batch(transactions)?;
  39. self.0.apply_batch(batch)?;
  40. Ok(ret)
  41. }
  42. /// Generate the sled batch corresponding to an insert, so caller
  43. /// can handle the write operation.
  44. /// The transactions are hashed with BLAKE3 and this hash is used as
  45. /// the key, while the value is the serialized [`Transaction`] itself.
  46. /// On success, the function returns the transaction hashes in the same
  47. /// order as the input transactions, along with the corresponding operation
  48. /// batch.
  49. pub fn insert_batch(
  50. &self,
  51. transactions: &[Transaction],
  52. ) -> Result<(sled::Batch, Vec<blake3::Hash>)> {
  53. let mut ret = Vec::with_capacity(transactions.len());
  54. let mut batch = sled::Batch::default();
  55. for tx in transactions {
  56. let serialized = serialize(tx);
  57. let tx_hash = blake3::hash(&serialized);
  58. batch.insert(tx_hash.as_bytes(), serialized);
  59. ret.push(tx_hash);
  60. }
  61. Ok((batch, ret))
  62. }
  63. /// Check if the txstore contains a given transaction hash.
  64. pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
  65. Ok(self.0.contains_key(tx_hash.as_bytes())?)
  66. }
  67. /// Fetch given tx hashes from the txstore.
  68. /// The resulting vector contains `Option`, which is `Some` if the tx
  69. /// was found in the txstore, and otherwise it is `None`, if it has not.
  70. /// The second parameter is a boolean which tells the function to fail in
  71. /// case at least one block was not found.
  72. pub fn get(
  73. &self,
  74. tx_hashes: &[blake3::Hash],
  75. strict: bool,
  76. ) -> Result<Vec<Option<Transaction>>> {
  77. let mut ret = Vec::with_capacity(tx_hashes.len());
  78. for tx_hash in tx_hashes {
  79. if let Some(found) = self.0.get(tx_hash.as_bytes())? {
  80. let tx = deserialize(&found)?;
  81. ret.push(Some(tx));
  82. } else {
  83. if strict {
  84. let s = tx_hash.to_hex().as_str().to_string();
  85. return Err(Error::TransactionNotFound(s))
  86. }
  87. ret.push(None);
  88. }
  89. }
  90. Ok(ret)
  91. }
  92. /// Retrieve all transactions from the txstore in the form of a tuple
  93. /// (`tx_hash`, `tx`).
  94. /// Be careful as this will try to load everything in memory.
  95. pub fn get_all(&self) -> Result<Vec<(blake3::Hash, Transaction)>> {
  96. let mut txs = vec![];
  97. for tx in self.0.iter() {
  98. let (key, value) = tx.unwrap();
  99. let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
  100. let tx = deserialize(&value)?;
  101. txs.push((hash_bytes.into(), tx));
  102. }
  103. Ok(txs)
  104. }
  105. /// Retrieve records count
  106. pub fn len(&self) -> usize {
  107. self.0.len()
  108. }
  109. pub fn is_empty(&self) -> bool {
  110. self.0.is_empty()
  111. }
  112. }
  113. /// Overlay structure over a [`TxStore`] instance.
  114. pub struct TxStoreOverlay(SledDbOverlayPtr);
  115. impl TxStoreOverlay {
  116. pub fn new(overlay: SledDbOverlayPtr) -> Result<Self> {
  117. overlay.lock().unwrap().open_tree(SLED_TX_TREE)?;
  118. Ok(Self(overlay))
  119. }
  120. /// Insert a slice of [`Transaction`] into the overlay.
  121. /// The transactions are hashed with BLAKE3 and this hash is used as
  122. /// the key, while the value is the serialized [`Transaction`] itself.
  123. /// On success, the function returns the transaction hashes in the same
  124. /// order as the input transactions.
  125. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  126. let mut ret = Vec::with_capacity(transactions.len());
  127. let mut lock = self.0.lock().unwrap();
  128. for tx in transactions {
  129. let serialized = serialize(tx);
  130. let tx_hash = blake3::hash(&serialized);
  131. lock.insert(SLED_TX_TREE, tx_hash.as_bytes(), &serialized)?;
  132. ret.push(tx_hash);
  133. }
  134. Ok(ret)
  135. }
  136. /// Fetch given tx hashes from the overlay.
  137. /// The resulting vector contains `Option`, which is `Some` if the tx
  138. /// was found in the overlay, and otherwise it is `None`, if it has not.
  139. /// The second parameter is a boolean which tells the function to fail in
  140. /// case at least one block was not found.
  141. pub fn get(
  142. &self,
  143. tx_hashes: &[blake3::Hash],
  144. strict: bool,
  145. ) -> Result<Vec<Option<Transaction>>> {
  146. let mut ret = Vec::with_capacity(tx_hashes.len());
  147. let lock = self.0.lock().unwrap();
  148. for tx_hash in tx_hashes {
  149. if let Some(found) = lock.get(SLED_TX_TREE, tx_hash.as_bytes())? {
  150. let tx = deserialize(&found)?;
  151. ret.push(Some(tx));
  152. } else {
  153. if strict {
  154. let s = tx_hash.to_hex().as_str().to_string();
  155. return Err(Error::TransactionNotFound(s))
  156. }
  157. ret.push(None);
  158. }
  159. }
  160. Ok(ret)
  161. }
  162. }
  163. /// The `PendingTxStore` is a `sled` tree storing all the node pending
  164. /// transactions where the key is the transaction hash, and the value is
  165. /// the serialized transaction.
  166. #[derive(Clone)]
  167. pub struct PendingTxStore(pub sled::Tree);
  168. impl PendingTxStore {
  169. /// Opens a new or existing `PendingTxStore` on the given sled database.
  170. pub fn new(db: &sled::Db) -> Result<Self> {
  171. let tree = db.open_tree(SLED_PENDING_TX_TREE)?;
  172. Ok(Self(tree))
  173. }
  174. /// Insert a slice of [`Transaction`] into the pending tx store.
  175. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  176. let (batch, ret) = self.insert_batch(transactions)?;
  177. self.0.apply_batch(batch)?;
  178. Ok(ret)
  179. }
  180. /// Generate the sled batch corresponding to an insert, so caller
  181. /// can handle the write operation.
  182. /// The transactions are hashed with BLAKE3 and this hash is used as
  183. /// the key, while the value is the serialized [`Transaction`] itself.
  184. /// On success, the function returns the transaction hashes in the same
  185. /// order as the input transactions, along with the corresponding operation
  186. /// batch.
  187. pub fn insert_batch(
  188. &self,
  189. transactions: &[Transaction],
  190. ) -> Result<(sled::Batch, Vec<blake3::Hash>)> {
  191. let mut ret = Vec::with_capacity(transactions.len());
  192. let mut batch = sled::Batch::default();
  193. for tx in transactions {
  194. let serialized = serialize(tx);
  195. let tx_hash = blake3::hash(&serialized);
  196. batch.insert(tx_hash.as_bytes(), serialized);
  197. ret.push(tx_hash);
  198. }
  199. Ok((batch, ret))
  200. }
  201. /// Check if the pending tx store contains a given transaction hash.
  202. pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
  203. Ok(self.0.contains_key(tx_hash.as_bytes())?)
  204. }
  205. /// Retrieve all transactions from the pending tx store in the form of
  206. /// a HashMap with key the transaction hash and value the transaction
  207. /// itself.
  208. /// Be careful as this will try to load everything in memory.
  209. pub fn get_all(&self) -> Result<HashMap<blake3::Hash, Transaction>> {
  210. let mut txs = HashMap::new();
  211. for tx in self.0.iter() {
  212. let (key, value) = tx.unwrap();
  213. let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
  214. let tx = deserialize(&value)?;
  215. txs.insert(hash_bytes.into(), tx);
  216. }
  217. Ok(txs)
  218. }
  219. /// Remove a slice of [`blake3::Hash`] from the pending tx store.
  220. pub fn remove(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
  221. let batch = self.remove_batch(txs_hashes);
  222. self.0.apply_batch(batch)?;
  223. Ok(())
  224. }
  225. /// Generate the sled batch corresponding to a remove, so caller
  226. /// can handle the write operation.
  227. pub fn remove_batch(&self, txs_hashes: &[blake3::Hash]) -> sled::Batch {
  228. let mut batch = sled::Batch::default();
  229. for tx_hash in txs_hashes {
  230. batch.remove(tx_hash.as_bytes());
  231. }
  232. batch
  233. }
  234. }
  235. /// The `PendingTxOrderStore` is a `sled` tree storing the order of all
  236. /// the node pending transactions where the key is an incremental value,
  237. /// and the value is the serialized transaction.
  238. #[derive(Clone)]
  239. pub struct PendingTxOrderStore(pub sled::Tree);
  240. impl PendingTxOrderStore {
  241. /// Opens a new or existing `PendingTxOrderStore` on the given sled database.
  242. pub fn new(db: &sled::Db) -> Result<Self> {
  243. let tree = db.open_tree(SLED_PENDING_TX_ORDER_TREE)?;
  244. Ok(Self(tree))
  245. }
  246. /// Insert a slice of [`blake3::Hash`] into the pending tx order store.
  247. /// With sled, the operation is done as a batch.
  248. pub fn insert(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
  249. let batch = self.insert_batch(txs_hashes)?;
  250. self.0.apply_batch(batch)?;
  251. Ok(())
  252. }
  253. /// Generate the sled batch corresponding to an insert, so caller
  254. /// can handle the write operation.
  255. pub fn insert_batch(&self, txs_hashes: &[blake3::Hash]) -> Result<sled::Batch> {
  256. let mut batch = sled::Batch::default();
  257. let mut next_index = match self.0.last()? {
  258. Some(n) => {
  259. let prev_bytes: [u8; 8] = n.0.as_ref().try_into().unwrap();
  260. let prev = u64::from_be_bytes(prev_bytes);
  261. prev + 1
  262. }
  263. None => 0,
  264. };
  265. for txs_hash in txs_hashes {
  266. batch.insert(&next_index.to_be_bytes(), txs_hash.as_bytes());
  267. next_index += 1;
  268. }
  269. Ok(batch)
  270. }
  271. /// Retrieve all transactions from the pending tx order store in the form
  272. /// of a tuple (`u64`, `blake3::Hash`).
  273. /// Be careful as this will try to load everything in memory.
  274. pub fn get_all(&self) -> Result<Vec<(u64, blake3::Hash)>> {
  275. let mut txs = vec![];
  276. for tx in self.0.iter() {
  277. let (key, value) = tx.unwrap();
  278. let index_bytes: [u8; 8] = key.as_ref().try_into().unwrap();
  279. let hash_bytes: [u8; 32] = value.as_ref().try_into().unwrap();
  280. let index = u64::from_be_bytes(index_bytes);
  281. let hash = blake3::Hash::from(hash_bytes);
  282. txs.push((index, hash));
  283. }
  284. Ok(txs)
  285. }
  286. /// Remove a slice of [`u64`] from the pending tx order store.
  287. pub fn remove(&self, indexes: &[u64]) -> Result<()> {
  288. let batch = self.remove_batch(indexes);
  289. self.0.apply_batch(batch)?;
  290. Ok(())
  291. }
  292. /// Generate the sled batch corresponding to a remove, so caller
  293. /// can handle the write operation.
  294. pub fn remove_batch(&self, indexes: &[u64]) -> sled::Batch {
  295. let mut batch = sled::Batch::default();
  296. for index in indexes {
  297. batch.remove(&index.to_be_bytes());
  298. }
  299. batch
  300. }
  301. }