txstore.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 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. /// The `TxStore` is a `sled` tree storing all the blockchain's
  22. /// transactions where the key is the transaction hash, and the value is
  23. /// the serialized transaction.
  24. #[derive(Clone)]
  25. pub struct TxStore(sled::Tree);
  26. impl TxStore {
  27. /// Opens a new or existing `TxStore` on the given sled database.
  28. pub fn new(db: &sled::Db) -> Result<Self> {
  29. let tree = db.open_tree(SLED_TX_TREE)?;
  30. Ok(Self(tree))
  31. }
  32. /// Insert a slice of [`Transaction`] into the txstore. With sled, the
  33. /// operation is done as a batch.
  34. /// The transactions are hashed with BLAKE3 and this hash is used as
  35. /// the key, while the value is the serialized [`Transaction`] itself.
  36. /// On success, the function returns the transaction hashes in the same
  37. /// order as the input transactions.
  38. pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
  39. let mut ret = Vec::with_capacity(transactions.len());
  40. let mut batch = sled::Batch::default();
  41. for tx in transactions {
  42. let serialized = serialize(tx);
  43. let txhash = blake3::hash(&serialized);
  44. batch.insert(txhash.as_bytes(), serialized);
  45. ret.push(txhash);
  46. }
  47. self.0.apply_batch(batch)?;
  48. Ok(ret)
  49. }
  50. /// Check if the txstore contains a given transaction hash.
  51. pub fn contains(&self, txid: &blake3::Hash) -> Result<bool> {
  52. Ok(self.0.contains_key(txid.as_bytes())?)
  53. }
  54. /// Fetch given tx hashes from the txstore.
  55. /// The resulting vector contains `Option`, which is `Some` if the tx
  56. /// was found in the txstore, and otherwise it is `None`, if it has not.
  57. /// The second parameter is a boolean which tells the function to fail in
  58. /// case at least one block was not found.
  59. pub fn get(&self, txids: &[blake3::Hash], strict: bool) -> Result<Vec<Option<Transaction>>> {
  60. let mut ret = Vec::with_capacity(txids.len());
  61. for txid in txids {
  62. if let Some(found) = self.0.get(txid.as_bytes())? {
  63. let tx = deserialize(&found)?;
  64. ret.push(Some(tx));
  65. } else {
  66. if strict {
  67. let s = txid.to_hex().as_str().to_string();
  68. return Err(Error::TransactionNotFound(s))
  69. }
  70. ret.push(None);
  71. }
  72. }
  73. Ok(ret)
  74. }
  75. /// Retrieve all transactions from the txstore in the form of a tuple
  76. /// (`tx_hash`, `tx`).
  77. /// Be careful as this will try to load everything in memory.
  78. pub fn get_all(&self) -> Result<Vec<(blake3::Hash, Transaction)>> {
  79. let mut txs = vec![];
  80. for tx in self.0.iter() {
  81. let (key, value) = tx.unwrap();
  82. let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
  83. let tx = deserialize(&value)?;
  84. txs.push((hash_bytes.into(), tx));
  85. }
  86. Ok(txs)
  87. }
  88. }