garbage_collect.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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::{error::TxVerifyFailed, validator::verification::verify_transactions, Error, Result};
  19. use darkfi_sdk::crypto::MerkleTree;
  20. use tracing::{debug, error, info};
  21. use crate::DarkfiNodePtr;
  22. /// Async task used for purging erroneous pending transactions from the nodes mempool.
  23. pub async fn garbage_collect_task(node: DarkfiNodePtr) -> Result<()> {
  24. info!(target: "darkfid::task::garbage_collect_task", "Starting garbage collection task...");
  25. // Grab all current unproposed transactions. We verify them in batches,
  26. // to not load them all in memory.
  27. let (mut last_checked, mut txs) =
  28. match node.validator.blockchain.transactions.get_after_pending(0, node.txs_batch_size) {
  29. Ok(pair) => pair,
  30. Err(e) => {
  31. error!(
  32. target: "darkfid::task::garbage_collect_task",
  33. "Uproposed transactions retrieval failed: {e}"
  34. );
  35. return Ok(())
  36. }
  37. };
  38. while !txs.is_empty() {
  39. // Verify each one against current forks
  40. for tx in txs {
  41. let tx_hash = tx.hash();
  42. let tx_vec = [tx.clone()];
  43. let mut valid = false;
  44. // Grab a lock over current consensus forks state
  45. let mut forks = node.validator.consensus.forks.write().await;
  46. // Iterate over them to verify transaction validity in their overlays
  47. for fork in forks.iter_mut() {
  48. // Clone forks' overlay
  49. let overlay = match fork.overlay.lock().unwrap().full_clone() {
  50. Ok(o) => o,
  51. Err(e) => {
  52. error!(
  53. target: "darkfid::task::garbage_collect_task",
  54. "Overlay full clone creation failed: {e}"
  55. );
  56. return Err(e)
  57. }
  58. };
  59. // Grab all current proposals transactions hashes
  60. let proposals_txs =
  61. match overlay.lock().unwrap().get_blocks_txs_hashes(&fork.proposals) {
  62. Ok(txs) => txs,
  63. Err(e) => {
  64. error!(
  65. target: "darkfid::task::garbage_collect_task",
  66. "Proposal transactions retrieval failed: {e}"
  67. );
  68. return Err(e)
  69. }
  70. };
  71. // If the hash is contained in the proposals transactions vec, skip it
  72. if proposals_txs.contains(&tx_hash) {
  73. continue
  74. }
  75. // Grab forks' next block height
  76. let next_block_height = match fork.get_next_block_height() {
  77. Ok(h) => h,
  78. Err(e) => {
  79. error!(
  80. target: "darkfid::task::garbage_collect_task",
  81. "Next fork block height retrieval failed: {e}"
  82. );
  83. return Err(e)
  84. }
  85. };
  86. // Verify transaction
  87. match verify_transactions(
  88. &overlay,
  89. next_block_height,
  90. node.validator.consensus.module.read().await.target,
  91. &tx_vec,
  92. &mut MerkleTree::new(1),
  93. false,
  94. )
  95. .await
  96. {
  97. Ok(_) => valid = true,
  98. Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {
  99. // Remove transaction from fork's mempool
  100. fork.mempool.retain(|tx| *tx != tx_hash);
  101. }
  102. Err(e) => {
  103. error!(
  104. target: "darkfid::task::garbage_collect_task",
  105. "Verifying transaction {tx_hash} failed: {e}"
  106. );
  107. return Err(e)
  108. }
  109. }
  110. }
  111. // Drop forks lock
  112. drop(forks);
  113. // Remove transaction if its invalid for all the forks
  114. if !valid {
  115. debug!(target: "darkfid::task::garbage_collect_task", "Removing invalid transaction: {tx_hash}");
  116. if let Err(e) = node.validator.blockchain.remove_pending_txs_hashes(&[tx_hash]) {
  117. error!(
  118. target: "darkfid::task::garbage_collect_task",
  119. "Removing invalid transaction {tx_hash} failed: {e}"
  120. );
  121. };
  122. }
  123. }
  124. // Grab next batch
  125. (last_checked, txs) = match node
  126. .validator
  127. .blockchain
  128. .transactions
  129. .get_after_pending(last_checked + node.txs_batch_size as u64, node.txs_batch_size)
  130. {
  131. Ok(pair) => pair,
  132. Err(e) => {
  133. error!(
  134. target: "darkfid::task::garbage_collect_task",
  135. "Uproposed transactions next batch retrieval failed: {e}"
  136. );
  137. break
  138. }
  139. };
  140. }
  141. info!(target: "darkfid::task::garbage_collect_task", "Garbage collection finished successfully!");
  142. Ok(())
  143. }