tx_store.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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 darkfi_serial::{deserialize, serialize};
  19. use crate::{tx::Transaction, Error, Result};
  20. const SLED_TX_TREE: &[u8] = b"_transactions";
  21. const SLED_ERRONEOUS_TX_TREE: &[u8] = b"_erroneous_transactions";
  22. /// The `TxStore` is a `sled` tree storing all the blockchain's
  23. /// transactions where the key is the transaction hash, and the value is
  24. /// the serialized transaction.
  25. #[derive(Clone)]
  26. pub struct TxStore(sled::Tree);
  27. impl TxStore {
  28. /// Opens a new or existing `TxStore` on the given sled database.
  29. pub fn new(db: &sled::Db) -> Result<Self> {
  30. let tree = db.open_tree(SLED_TX_TREE)?;
  31. Ok(Self(tree))
  32. }
  33. /// Insert a slice of [`Transaction`] into the txstore. With sled, the
  34. /// operation is done as a batch.
  35. /// The transactions are hashed with BLAKE3 and this hash is used as
  36. /// the key, while the value is the serialized [`Transaction`] itself.
  37. /// On success, the function returns the transaction hashes in the same
  38. /// order as the input transactions.
  39. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  40. let mut ret = Vec::with_capacity(transactions.len());
  41. let mut batch = sled::Batch::default();
  42. for tx in transactions {
  43. let serialized = serialize(tx);
  44. let tx_hash = blake3::hash(&serialized);
  45. batch.insert(tx_hash.as_bytes(), serialized);
  46. ret.push(tx_hash);
  47. }
  48. self.0.apply_batch(batch)?;
  49. Ok(ret)
  50. }
  51. /// Check if the txstore contains a given transaction hash.
  52. pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
  53. Ok(self.0.contains_key(tx_hash.as_bytes())?)
  54. }
  55. /// Fetch given tx hashes from the txstore.
  56. /// The resulting vector contains `Option`, which is `Some` if the tx
  57. /// was found in the txstore, 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 block was not found.
  60. pub fn get(
  61. &self,
  62. tx_hashes: &[blake3::Hash],
  63. strict: bool,
  64. ) -> Result<Vec<Option<Transaction>>> {
  65. let mut ret = Vec::with_capacity(tx_hashes.len());
  66. for tx_hash in tx_hashes {
  67. if let Some(found) = self.0.get(tx_hash.as_bytes())? {
  68. let tx = deserialize(&found)?;
  69. ret.push(Some(tx));
  70. } else {
  71. if strict {
  72. let s = tx_hash.to_hex().as_str().to_string();
  73. return Err(Error::TransactionNotFound(s))
  74. }
  75. ret.push(None);
  76. }
  77. }
  78. Ok(ret)
  79. }
  80. /// Retrieve all transactions from the txstore in the form of a tuple
  81. /// (`tx_hash`, `tx`).
  82. /// Be careful as this will try to load everything in memory.
  83. pub fn get_all(&self) -> Result<Vec<(blake3::Hash, Transaction)>> {
  84. let mut txs = vec![];
  85. for tx in self.0.iter() {
  86. let (key, value) = tx.unwrap();
  87. let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
  88. let tx = deserialize(&value)?;
  89. txs.push((hash_bytes.into(), tx));
  90. }
  91. Ok(txs)
  92. }
  93. }
  94. /// The `ErroneousTxStore` is a `sled` tree storing all the blockchain's
  95. /// erroneous transactions where the key is the transaction hash, and the value is
  96. /// an empty slice.
  97. #[derive(Clone)]
  98. pub struct ErroneousTxStore(sled::Tree);
  99. impl ErroneousTxStore {
  100. /// Opens a new or existing `ErroneousTxStore` on the given sled database.
  101. pub fn new(db: &sled::Db) -> Result<Self> {
  102. let tree = db.open_tree(SLED_ERRONEOUS_TX_TREE)?;
  103. Ok(Self(tree))
  104. }
  105. /// Insert a slice of [`Transaction`] into the erroneoustxstore. With sled, the
  106. /// operation is done as a batch.
  107. /// The transactions are hashed with BLAKE3 and this hash is used as
  108. /// the key, while the value is an empty slice.
  109. /// On success, the function returns the transaction hashes in the same
  110. /// order as the input transactions.
  111. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  112. let mut ret = Vec::with_capacity(transactions.len());
  113. let mut batch = sled::Batch::default();
  114. for tx in transactions {
  115. let serialized = serialize(tx);
  116. let tx_hash = blake3::hash(&serialized);
  117. batch.insert(tx_hash.as_bytes(), &[]);
  118. ret.push(tx_hash);
  119. }
  120. self.0.apply_batch(batch)?;
  121. Ok(ret)
  122. }
  123. /// Check if the erroneoustxstore contains a given transaction hash.
  124. pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
  125. Ok(self.0.contains_key(tx_hash.as_bytes())?)
  126. }
  127. /// Retrieve all erroneous transaction hashes from the erroneoustxstore.
  128. /// Be careful as this will try to load everything in memory.
  129. pub fn get_all(&self) -> Result<Vec<blake3::Hash>> {
  130. let mut txs = vec![];
  131. for tx in self.0.iter() {
  132. let (key, _) = tx.unwrap();
  133. let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
  134. txs.push(hash_bytes.into());
  135. }
  136. Ok(txs)
  137. }
  138. }