Prechádzať zdrojové kódy

blockchain/tx_store: unified main tree with the pending tree into single store structure

skoupidi 2 rokov pred
rodič
commit
70aeb839f5

+ 12 - 20
src/blockchain/mod.rs

@@ -38,7 +38,7 @@ pub use header_store::{Header, HeaderStore, HeaderStoreOverlay};
 
 /// Transactions related storage implementations
 pub mod tx_store;
-pub use tx_store::{PendingTxOrderStore, PendingTxStore, TxStore, TxStoreOverlay};
+pub use tx_store::{TxStore, TxStoreOverlay};
 
 /// Contracts and Wasm storage implementations
 pub mod contract_store;
@@ -59,12 +59,8 @@ pub struct Blockchain {
     pub order: BlockOrderStore,
     /// Block height difficulties sled tree,
     pub difficulties: BlockDifficultyStore,
-    /// Transactions sled tree
+    /// Transactions related sled trees
     pub transactions: TxStore,
-    /// Pending transactions sled tree
-    pub pending_txs: PendingTxStore,
-    /// Pending transactions order sled tree
-    pub pending_txs_order: PendingTxOrderStore,
     /// Contract states
     pub contracts: ContractStateStore,
     /// Wasm bincodes
@@ -79,8 +75,6 @@ impl Blockchain {
         let order = BlockOrderStore::new(db)?;
         let difficulties = BlockDifficultyStore::new(db)?;
         let transactions = TxStore::new(db)?;
-        let pending_txs = PendingTxStore::new(db)?;
-        let pending_txs_order = PendingTxOrderStore::new(db)?;
         let contracts = ContractStateStore::new(db)?;
         let wasm_bincode = WasmStore::new(db)?;
 
@@ -91,8 +85,6 @@ impl Blockchain {
             order,
             difficulties,
             transactions,
-            pending_txs,
-            pending_txs_order,
             contracts,
             wasm_bincode,
         })
@@ -109,7 +101,7 @@ impl Blockchain {
 
         // Store transactions
         let (txs_batch, _) = self.transactions.insert_batch(&block.txs)?;
-        trees.push(self.transactions.0.clone());
+        trees.push(self.transactions.main.clone());
         batches.push(txs_batch);
 
         // Store header
@@ -264,11 +256,11 @@ impl Blockchain {
     /// On success, the function returns the transaction hashes in the same order
     /// as the input transactions.
     pub fn add_pending_txs(&self, txs: &[Transaction]) -> Result<Vec<blake3::Hash>> {
-        let (txs_batch, txs_hashes) = self.pending_txs.insert_batch(txs)?;
-        let txs_order_batch = self.pending_txs_order.insert_batch(&txs_hashes)?;
+        let (txs_batch, txs_hashes) = self.transactions.insert_batch_pending(txs)?;
+        let txs_order_batch = self.transactions.insert_batch_pending_order(&txs_hashes)?;
 
         // Perform an atomic transaction over the trees and apply the batches.
-        let trees = [self.pending_txs.0.clone(), self.pending_txs_order.0.clone()];
+        let trees = [self.transactions.pending.clone(), self.transactions.pending_order.clone()];
         let batches = [txs_batch, txs_order_batch];
         self.atomic_write(&trees, &batches)?;
 
@@ -278,8 +270,8 @@ impl Blockchain {
     /// Retrieve all transactions from the pending tx store.
     /// Be careful as this will try to load everything in memory.
     pub fn get_pending_txs(&self) -> Result<Vec<Transaction>> {
-        let txs = self.pending_txs.get_all()?;
-        let indexes = self.pending_txs_order.get_all()?;
+        let txs = self.transactions.get_all_pending()?;
+        let indexes = self.transactions.get_all_pending_order()?;
         if txs.len() != indexes.len() {
             return Err(Error::InvalidInputLengths)
         }
@@ -296,7 +288,7 @@ impl Blockchain {
     pub fn remove_pending_txs(&self, txs: &[Transaction]) -> Result<()> {
         let txs_hashes: Vec<blake3::Hash> =
             txs.iter().map(|x| blake3::hash(&serialize(x))).collect();
-        let indexes = self.pending_txs_order.get_all()?;
+        let indexes = self.transactions.get_all_pending_order()?;
         // We could do indexes.iter().map(|x| txs_hashes.contains(x.1)).collect.map(|x| x.0).collect
         // but this is faster since we don't do the second iteration
         let mut removed_indexes = vec![];
@@ -306,11 +298,11 @@ impl Blockchain {
             }
         }
 
-        let txs_batch = self.pending_txs.remove_batch(&txs_hashes);
-        let txs_order_batch = self.pending_txs_order.remove_batch(&removed_indexes);
+        let txs_batch = self.transactions.remove_batch_pending(&txs_hashes);
+        let txs_order_batch = self.transactions.remove_batch_pending_order(&removed_indexes);
 
         // Perform an atomic transaction over the trees and apply the batches.
-        let trees = [self.pending_txs.0.clone(), self.pending_txs_order.0.clone()];
+        let trees = [self.transactions.pending.clone(), self.transactions.pending_order.clone()];
         let batches = [txs_batch, txs_order_batch];
         self.atomic_write(&trees, &batches)?;
 

+ 198 - 211
src/blockchain/tx_store.rs

@@ -28,28 +28,57 @@ const SLED_TX_TREE: &[u8] = b"_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
-/// transactions where the key is the transaction hash, and the value is
-/// the serialized transaction.
+/// The `TxStore` is a structure representing all `sled` trees related
+/// to storing the blockchain's transactions information.
 #[derive(Clone)]
-pub struct TxStore(pub sled::Tree);
+pub struct TxStore {
+    /// Main `sled` tree, storing all the blockchain's transactions, where
+    /// the key is the transaction hash, and the value is the serialized
+    /// transaction.
+    pub main: sled::Tree,
+    /// The `sled` tree storing all the node pending transactions, where
+    /// the key is the transaction hash, and the value is the serialized
+    /// transaction.
+    pub pending: sled::Tree,
+    /// The `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.
+    pub pending_order: sled::Tree,
+}
 
 impl TxStore {
     /// Opens a new or existing `TxStore` on the given sled database.
     pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_TX_TREE)?;
-        Ok(Self(tree))
+        let main = db.open_tree(SLED_TX_TREE)?;
+        let pending = db.open_tree(SLED_PENDING_TX_TREE)?;
+        let pending_order = db.open_tree(SLED_PENDING_TX_ORDER_TREE)?;
+        Ok(Self { main, pending, pending_order })
     }
 
-    /// Insert a slice of [`Transaction`] into the txstore.
+    /// Insert a slice of [`Transaction`] into the store's main tree.
     pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
         let (batch, ret) = self.insert_batch(transactions)?;
-        self.0.apply_batch(batch)?;
+        self.main.apply_batch(batch)?;
+        Ok(ret)
+    }
+
+    /// Insert a slice of [`Transaction`] into the store's pending txs tree.
+    pub fn insert_pending(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
+        let (batch, ret) = self.insert_batch_pending(transactions)?;
+        self.pending.apply_batch(batch)?;
         Ok(ret)
     }
 
-    /// Generate the sled batch corresponding to an insert, so caller
-    /// can handle the write operation.
+    /// Insert a slice of [`blake3::Hash`] into the store's pending txs order tree.
+    /// With sled, the operation is done as a batch.
+    pub fn insert_pending_order(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
+        let batch = self.insert_batch_pending_order(txs_hashes)?;
+        self.pending_order.apply_batch(batch)?;
+        Ok(())
+    }
+
+    /// Generate the sled batch corresponding to an insert to the main tree,
+    /// so caller can handle the write operation.
     /// The transactions are hashed with BLAKE3 and this hash is used as
     /// the key, while the value is the serialized [`Transaction`] itself.
     /// On success, the function returns the transaction hashes in the same
@@ -72,12 +101,63 @@ impl TxStore {
         Ok((batch, ret))
     }
 
-    /// Check if the txstore contains a given transaction hash.
+    /// Generate the sled batch corresponding to an insert to the pending txs tree,
+    /// so caller can handle the write operation.
+    /// The transactions are hashed with BLAKE3 and this hash is used as
+    /// the key, while the value is the serialized [`Transaction`] itself.
+    /// On success, the function returns the transaction hashes in the same
+    /// order as the input transactions, along with the corresponding operation
+    /// batch.
+    pub fn insert_batch_pending(
+        &self,
+        transactions: &[Transaction],
+    ) -> Result<(sled::Batch, Vec<blake3::Hash>)> {
+        let mut ret = Vec::with_capacity(transactions.len());
+        let mut batch = sled::Batch::default();
+
+        for tx in transactions {
+            let serialized = serialize(tx);
+            let tx_hash = blake3::hash(&serialized);
+            batch.insert(tx_hash.as_bytes(), serialized);
+            ret.push(tx_hash);
+        }
+
+        Ok((batch, ret))
+    }
+
+    /// Generate the sled batch corresponding to an insert to the pending txs
+    /// order tree, so caller can handle the write operation.
+    pub fn insert_batch_pending_order(&self, txs_hashes: &[blake3::Hash]) -> Result<sled::Batch> {
+        let mut batch = sled::Batch::default();
+
+        let mut next_index = match self.pending_order.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;
+        }
+
+        Ok(batch)
+    }
+
+    /// Check if the store's main tree contains a given transaction hash.
     pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
-        Ok(self.0.contains_key(tx_hash.as_bytes())?)
+        Ok(self.main.contains_key(tx_hash.as_bytes())?)
     }
 
-    /// Fetch given tx hashes from the txstore.
+    /// Check if the store's pending txs tree contains a given transaction hash.
+    pub fn contains_pending(&self, tx_hash: &blake3::Hash) -> Result<bool> {
+        Ok(self.pending.contains_key(tx_hash.as_bytes())?)
+    }
+
+    /// Fetch given tx hashes from the store's main tree.
     /// The resulting vector contains `Option`, which is `Some` if the tx
     /// was found in the txstore, and otherwise it is `None`, if it has not.
     /// The second parameter is a boolean which tells the function to fail in
@@ -90,7 +170,7 @@ impl TxStore {
         let mut ret = Vec::with_capacity(tx_hashes.len());
 
         for tx_hash in tx_hashes {
-            if let Some(found) = self.0.get(tx_hash.as_bytes())? {
+            if let Some(found) = self.main.get(tx_hash.as_bytes())? {
                 let tx = deserialize(&found)?;
                 ret.push(Some(tx));
                 continue
@@ -105,26 +185,121 @@ impl TxStore {
         Ok(ret)
     }
 
-    /// Retrieve all transactions from the txstore in the form of a tuple
-    /// (`tx_hash`, `tx`).
+    /// Fetch given tx hashes from the store's pending txs tree.
+    /// The resulting vector contains `Option`, which is `Some` if the tx
+    /// was found in the pending tx store, and otherwise it is `None`, if it has not.
+    /// The second parameter is a boolean which tells the function to fail in
+    /// case at least one tx was not found.
+    pub fn get_pending(
+        &self,
+        tx_hashes: &[blake3::Hash],
+        strict: bool,
+    ) -> Result<Vec<Option<Transaction>>> {
+        let mut ret = Vec::with_capacity(tx_hashes.len());
+
+        for tx_hash in tx_hashes {
+            if let Some(found) = self.pending.get(tx_hash.as_bytes())? {
+                let tx = deserialize(&found)?;
+                ret.push(Some(tx));
+                continue
+            }
+            if strict {
+                let s = tx_hash.to_hex().as_str().to_string();
+                return Err(Error::TransactionNotFound(s))
+            }
+            ret.push(None);
+        }
+
+        Ok(ret)
+    }
+
+    /// Retrieve all transactions from the store's main tree in the form of
+    /// a tuple (`tx_hash`, `tx`).
     /// 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![];
 
-        for tx in self.0.iter() {
+        for tx in self.main.iter() {
             txs.push(parse_record(tx.unwrap())?);
         }
 
         Ok(txs)
     }
 
-    /// Retrieve records count
+    /// Retrieve all transactions from the store's pending txs tree 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.
+    pub fn get_all_pending(&self) -> Result<HashMap<blake3::Hash, Transaction>> {
+        let mut txs = HashMap::new();
+
+        for tx in self.pending.iter() {
+            let (key, value) = parse_record(tx.unwrap())?;
+            txs.insert(key, value);
+        }
+
+        Ok(txs)
+    }
+
+    /// Retrieve all transactions from the store's pending txs order tree in
+    /// the form of a tuple (`u64`, `blake3::Hash`).
+    /// Be careful as this will try to load everything in memory.
+    pub fn get_all_pending_order(&self) -> Result<Vec<(u64, blake3::Hash)>> {
+        let mut txs = vec![];
+
+        for tx in self.pending_order.iter() {
+            txs.push(parse_u64_key_record(tx.unwrap())?);
+        }
+
+        Ok(txs)
+    }
+
+    /// Retrieve records count of the store's main tree.
     pub fn len(&self) -> usize {
-        self.0.len()
+        self.main.len()
     }
 
+    /// Check if the store's main tree is empty.
     pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
+        self.main.is_empty()
+    }
+
+    /// Remove a slice of [`blake3::Hash`] from the store's pending txs tree.
+    pub fn remove_pending(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
+        let batch = self.remove_batch_pending(txs_hashes);
+        self.pending.apply_batch(batch)?;
+        Ok(())
+    }
+
+    /// Remove a slice of [`u64`] from the store's pending txs order tree.
+    pub fn remove_pending_order(&self, indexes: &[u64]) -> Result<()> {
+        let batch = self.remove_batch_pending_order(indexes);
+        self.pending_order.apply_batch(batch)?;
+        Ok(())
+    }
+
+    /// Generate the sled batch corresponding to a remove from the store's pending
+    /// txs tree, so caller can handle the write operation.
+    pub fn remove_batch_pending(&self, txs_hashes: &[blake3::Hash]) -> sled::Batch {
+        let mut batch = sled::Batch::default();
+
+        for tx_hash in txs_hashes {
+            batch.remove(tx_hash.as_bytes());
+        }
+
+        batch
+    }
+
+    /// Generate the sled batch corresponding to a remove from the store's pending
+    /// txs order tree, so caller can handle the write operation.
+    pub fn remove_batch_pending_order(&self, indexes: &[u64]) -> sled::Batch {
+        let mut batch = sled::Batch::default();
+
+        for index in indexes {
+            batch.remove(&index.to_be_bytes());
+        }
+
+        batch
     }
 }
 
@@ -137,7 +312,7 @@ impl TxStoreOverlay {
         Ok(Self(overlay.clone()))
     }
 
-    /// Insert a slice of [`Transaction`] into the overlay.
+    /// Insert a slice of [`Transaction`] into the overlay's main tree.
     /// The transactions are hashed with BLAKE3 and this hash is used as
     /// the key, while the value is the serialized [`Transaction`] itself.
     /// On success, the function returns the transaction hashes in the same
@@ -156,7 +331,7 @@ impl TxStoreOverlay {
         Ok(ret)
     }
 
-    /// Fetch given tx hashes from the overlay.
+    /// Fetch given tx hashes from the overlay's main tree.
     /// The resulting vector contains `Option`, which is `Some` if the tx
     /// was found in the overlay, and otherwise it is `None`, if it has not.
     /// The second parameter is a boolean which tells the function to fail in
@@ -185,7 +360,7 @@ impl TxStoreOverlay {
         Ok(ret)
     }
 
-    /// Fetch given tx hash from the overlay. This function uses
+    /// Fetch given tx hash from the overlay's main tree. This function uses
     /// raw bytes as input and doesn't deserialize the retrieved value.
     /// The resulting vector contains `Option`, which is `Some` if the tx
     /// was found in the overlay, and otherwise it is `None`, if it has not.
@@ -197,191 +372,3 @@ impl TxStoreOverlay {
         Ok(None)
     }
 }
-
-/// The `PendingTxStore` is a `sled` tree storing all the node pending
-/// transactions where the key is the transaction hash, and the value is
-/// the serialized transaction.
-#[derive(Clone)]
-pub struct PendingTxStore(pub sled::Tree);
-
-impl PendingTxStore {
-    /// Opens a new or existing `PendingTxStore` on the given sled database.
-    pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_PENDING_TX_TREE)?;
-        Ok(Self(tree))
-    }
-
-    /// Insert a slice of [`Transaction`] into the pending tx store.   
-    pub fn insert(&self, transactions: &[Transaction]) -> Result<Vec<blake3::Hash>> {
-        let (batch, ret) = self.insert_batch(transactions)?;
-        self.0.apply_batch(batch)?;
-        Ok(ret)
-    }
-
-    /// Generate the sled batch corresponding to an insert, so caller
-    /// can handle the write operation.
-    /// The transactions are hashed with BLAKE3 and this hash is used as
-    /// the key, while the value is the serialized [`Transaction`] itself.
-    /// On success, the function returns the transaction hashes in the same
-    /// order as the input transactions, along with the corresponding operation
-    /// batch.
-    pub fn insert_batch(
-        &self,
-        transactions: &[Transaction],
-    ) -> Result<(sled::Batch, Vec<blake3::Hash>)> {
-        let mut ret = Vec::with_capacity(transactions.len());
-        let mut batch = sled::Batch::default();
-
-        for tx in transactions {
-            let serialized = serialize(tx);
-            let tx_hash = blake3::hash(&serialized);
-            batch.insert(tx_hash.as_bytes(), serialized);
-            ret.push(tx_hash);
-        }
-
-        Ok((batch, ret))
-    }
-
-    /// Check if the pending tx store contains a given transaction hash.
-    pub fn contains(&self, tx_hash: &blake3::Hash) -> Result<bool> {
-        Ok(self.0.contains_key(tx_hash.as_bytes())?)
-    }
-
-    /// Fetch given tx hashes from the pending tx store.
-    /// The resulting vector contains `Option`, which is `Some` if the tx
-    /// was found in the pending tx store, and otherwise it is `None`, if it has not.
-    /// The second parameter is a boolean which tells the function to fail in
-    /// case at least one tx was not found.
-    pub fn get(
-        &self,
-        tx_hashes: &[blake3::Hash],
-        strict: bool,
-    ) -> Result<Vec<Option<Transaction>>> {
-        let mut ret = Vec::with_capacity(tx_hashes.len());
-
-        for tx_hash in tx_hashes {
-            if let Some(found) = self.0.get(tx_hash.as_bytes())? {
-                let tx = deserialize(&found)?;
-                ret.push(Some(tx));
-                continue
-            }
-            if strict {
-                let s = tx_hash.to_hex().as_str().to_string();
-                return Err(Error::TransactionNotFound(s))
-            }
-            ret.push(None);
-        }
-
-        Ok(ret)
-    }
-
-    /// 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.
-    pub fn get_all(&self) -> Result<HashMap<blake3::Hash, Transaction>> {
-        let mut txs = HashMap::new();
-
-        for tx in self.0.iter() {
-            let (key, value) = parse_record(tx.unwrap())?;
-            txs.insert(key, value);
-        }
-
-        Ok(txs)
-    }
-
-    /// Remove a slice of [`blake3::Hash`] from the pending tx store.
-    pub fn remove(&self, txs_hashes: &[blake3::Hash]) -> Result<()> {
-        let batch = self.remove_batch(txs_hashes);
-        self.0.apply_batch(batch)?;
-        Ok(())
-    }
-
-    /// Generate the sled batch corresponding to a remove, so caller
-    /// can handle the write operation.
-    pub fn remove_batch(&self, txs_hashes: &[blake3::Hash]) -> sled::Batch {
-        let mut batch = sled::Batch::default();
-
-        for tx_hash in txs_hashes {
-            batch.remove(tx_hash.as_bytes());
-        }
-
-        batch
-    }
-}
-
-/// 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(pub 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 batch = self.insert_batch(txs_hashes)?;
-        self.0.apply_batch(batch)?;
-        Ok(())
-    }
-
-    /// Generate the sled batch corresponding to an insert, so caller
-    /// can handle the write operation.
-    pub fn insert_batch(&self, txs_hashes: &[blake3::Hash]) -> Result<sled::Batch> {
-        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;
-        }
-
-        Ok(batch)
-    }
-
-    /// 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.
-    pub fn get_all(&self) -> Result<Vec<(u64, blake3::Hash)>> {
-        let mut txs = vec![];
-
-        for tx in self.0.iter() {
-            txs.push(parse_u64_key_record(tx.unwrap())?);
-        }
-
-        Ok(txs)
-    }
-
-    /// Remove a slice of [`u64`] from the pending tx order store.
-    pub fn remove(&self, indexes: &[u64]) -> Result<()> {
-        let batch = self.remove_batch(indexes);
-        self.0.apply_batch(batch)?;
-        Ok(())
-    }
-
-    /// Generate the sled batch corresponding to a remove, so caller
-    /// can handle the write operation.
-    pub fn remove_batch(&self, indexes: &[u64]) -> sled::Batch {
-        let mut batch = sled::Batch::default();
-
-        for index in indexes {
-            batch.remove(&index.to_be_bytes());
-        }
-
-        batch
-    }
-}

+ 2 - 2
src/validator/consensus.rs

@@ -633,8 +633,8 @@ impl Fork {
 
         // Retrieve the actual unproposed transactions
         let mut unproposed_txs: Vec<Transaction> = blockchain
-            .pending_txs
-            .get(&unproposed_txs, true)?
+            .transactions
+            .get_pending(&unproposed_txs, true)?
             .iter()
             .map(|x| x.clone().unwrap())
             .collect();

+ 1 - 1
src/validator/mod.rs

@@ -135,7 +135,7 @@ impl Validator {
 
         // Check if we have already seen this tx
         let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
-        let tx_in_pending_txs_store = self.blockchain.pending_txs.contains(&tx_hash)?;
+        let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
 
         if tx_in_txstore || tx_in_pending_txs_store {
             info!(target: "validator::append_tx", "We have already seen this tx");