|
@@ -16,12 +16,15 @@
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
|
|
+use std::collections::HashMap;
|
|
|
|
|
+
|
|
|
use darkfi_serial::{deserialize, serialize};
|
|
use darkfi_serial::{deserialize, serialize};
|
|
|
|
|
|
|
|
use crate::{tx::Transaction, Error, Result};
|
|
use crate::{tx::Transaction, Error, Result};
|
|
|
|
|
|
|
|
const SLED_TX_TREE: &[u8] = b"_transactions";
|
|
const SLED_TX_TREE: &[u8] = b"_transactions";
|
|
|
const SLED_PENDING_TX_TREE: &[u8] = b"_pending_transactions";
|
|
const SLED_PENDING_TX_TREE: &[u8] = b"_pending_transactions";
|
|
|
|
|
+const SLED_PENDING_TX_ORDER_TREE: &[u8] = b"_pending_transactions_order";
|
|
|
|
|
|
|
|
/// The `TxStore` is a `sled` tree storing all the blockchain's
|
|
/// The `TxStore` is a `sled` tree storing all the blockchain's
|
|
|
/// transactions where the key is the transaction hash, and the value is
|
|
/// transactions where the key is the transaction hash, and the value is
|
|
@@ -146,40 +149,98 @@ impl PendingTxStore {
|
|
|
Ok(self.0.contains_key(tx_hash.as_bytes())?)
|
|
Ok(self.0.contains_key(tx_hash.as_bytes())?)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Retrieve all transactions from the pending tx store in the form of a tuple
|
|
|
|
|
- /// (`tx_hash`, `tx`).
|
|
|
|
|
|
|
+ /// Retrieve all transactions from the pending tx store in the form of
|
|
|
|
|
+ /// a HashMap with key the transaction hash and value the transaction
|
|
|
|
|
+ /// itself.
|
|
|
/// Be careful as this will try to load everything in memory.
|
|
/// Be careful as this will try to load everything in memory.
|
|
|
- pub fn get_all(&self) -> Result<Vec<(blake3::Hash, Transaction)>> {
|
|
|
|
|
- let mut txs = vec![];
|
|
|
|
|
|
|
+ pub fn get_all(&self) -> Result<HashMap<blake3::Hash, Transaction>> {
|
|
|
|
|
+ let mut txs = HashMap::new();
|
|
|
|
|
|
|
|
for tx in self.0.iter() {
|
|
for tx in self.0.iter() {
|
|
|
let (key, value) = tx.unwrap();
|
|
let (key, value) = tx.unwrap();
|
|
|
let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
|
|
let hash_bytes: [u8; 32] = key.as_ref().try_into().unwrap();
|
|
|
let tx = deserialize(&value)?;
|
|
let tx = deserialize(&value)?;
|
|
|
- txs.push((hash_bytes.into(), tx));
|
|
|
|
|
|
|
+ txs.insert(hash_bytes.into(), tx);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Ok(txs)
|
|
Ok(txs)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Retrieve all transactions from the pending tx store.
|
|
|
|
|
|
|
+ /// Remove a slice of [`blake3::Hash`] from the pending tx store.
|
|
|
|
|
+ /// With sled, the operation is done as a batch.
|
|
|
|
|
+ pub fn remove(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
|
|
|
|
|
+ let mut batch = sled::Batch::default();
|
|
|
|
|
+
|
|
|
|
|
+ for tx_hash in txs_hashes {
|
|
|
|
|
+ batch.remove(tx_hash.as_bytes());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ self.0.apply_batch(batch)?;
|
|
|
|
|
+ Ok(())
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// The `PendingTxOrderStore` is a `sled` tree storing the order of all
|
|
|
|
|
+/// the node pending transactions where the key is an incremental value,
|
|
|
|
|
+/// and the value is the serialized transaction.
|
|
|
|
|
+#[derive(Clone)]
|
|
|
|
|
+pub struct PendingTxOrderStore(sled::Tree);
|
|
|
|
|
+
|
|
|
|
|
+impl PendingTxOrderStore {
|
|
|
|
|
+ /// Opens a new or existing `PendingTxOrderStore` on the given sled database.
|
|
|
|
|
+ pub fn new(db: &sled::Db) -> Result<Self> {
|
|
|
|
|
+ let tree = db.open_tree(SLED_PENDING_TX_ORDER_TREE)?;
|
|
|
|
|
+ Ok(Self(tree))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Insert a slice of [`blake3::Hash`] into the pending tx order store.
|
|
|
|
|
+ /// With sled, the operation is done as a batch.
|
|
|
|
|
+ pub fn insert(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
|
|
|
|
|
+ let mut batch = sled::Batch::default();
|
|
|
|
|
+
|
|
|
|
|
+ let mut next_index = match self.0.last()? {
|
|
|
|
|
+ Some(n) => {
|
|
|
|
|
+ let prev_bytes: [u8; 8] = n.0.as_ref().try_into().unwrap();
|
|
|
|
|
+ let prev = u64::from_be_bytes(prev_bytes);
|
|
|
|
|
+ prev + 1
|
|
|
|
|
+ }
|
|
|
|
|
+ None => 0,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ for txs_hash in txs_hashes {
|
|
|
|
|
+ batch.insert(&next_index.to_be_bytes(), txs_hash.as_bytes());
|
|
|
|
|
+ next_index += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ self.0.apply_batch(batch)?;
|
|
|
|
|
+ Ok(())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Retrieve all transactions from the pending tx order store in the form
|
|
|
|
|
+ /// of a tuple (`u64`, `blake3::Hash`).
|
|
|
/// Be careful as this will try to load everything in memory.
|
|
/// Be careful as this will try to load everything in memory.
|
|
|
- pub fn get_all_txs(&self) -> Result<Vec<Transaction>> {
|
|
|
|
|
- let txs = self.get_all()?;
|
|
|
|
|
- Ok(txs.iter().map(|x| x.1.clone()).rev().collect())
|
|
|
|
|
|
|
+ pub fn get_all(&self) -> Result<Vec<(u64, blake3::Hash)>> {
|
|
|
|
|
+ let mut txs = vec![];
|
|
|
|
|
+
|
|
|
|
|
+ for tx in self.0.iter() {
|
|
|
|
|
+ let (key, value) = tx.unwrap();
|
|
|
|
|
+ let index_bytes: [u8; 8] = key.as_ref().try_into().unwrap();
|
|
|
|
|
+ let hash_bytes: [u8; 32] = value.as_ref().try_into().unwrap();
|
|
|
|
|
+ let index = u64::from_be_bytes(index_bytes);
|
|
|
|
|
+ let hash = blake3::Hash::from(hash_bytes);
|
|
|
|
|
+ txs.push((index, hash));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Ok(txs)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Remove a slice of [`Transaction`] from the pending tx store.
|
|
|
|
|
|
|
+ /// Remove a slice of [`u64`] from the pending tx order store.
|
|
|
/// With sled, the operation is done as a batch.
|
|
/// With sled, the operation is done as a batch.
|
|
|
- /// The transactions are hashed with BLAKE3 and this hash is used as
|
|
|
|
|
- /// the key to remove.
|
|
|
|
|
- pub fn remove(&self, transactions: &[Transaction]) -> Result<()> {
|
|
|
|
|
|
|
+ pub fn remove(&self, indexes: &[u64]) -> Result<()> {
|
|
|
let mut batch = sled::Batch::default();
|
|
let mut batch = sled::Batch::default();
|
|
|
|
|
|
|
|
- for tx in transactions {
|
|
|
|
|
- let serialized = serialize(tx);
|
|
|
|
|
- let tx_hash = blake3::hash(&serialized);
|
|
|
|
|
- batch.remove(tx_hash.as_bytes());
|
|
|
|
|
|
|
+ for index in indexes {
|
|
|
|
|
+ batch.remove(&index.to_be_bytes());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
self.0.apply_batch(batch)?;
|
|
self.0.apply_batch(batch)?;
|