darkfid/task/
garbage_collect.rs1use darkfi::{error::TxVerifyFailed, validator::verification::verify_transactions, Error, Result};
20use darkfi_sdk::crypto::MerkleTree;
21use tracing::{debug, error, info};
22
23use crate::DarkfiNodePtr;
24
25pub async fn garbage_collect_task(node: DarkfiNodePtr) -> Result<()> {
27 info!(target: "darkfid::task::garbage_collect_task", "Starting garbage collection task...");
28
29 let (mut last_checked, mut txs) =
32 match node.validator.blockchain.transactions.get_after_pending(0, node.txs_batch_size) {
33 Ok(pair) => pair,
34 Err(e) => {
35 error!(
36 target: "darkfid::task::garbage_collect_task",
37 "Uproposed transactions retrieval failed: {e}"
38 );
39 return Ok(())
40 }
41 };
42
43 if txs.is_empty() {
45 info!(target: "darkfid::task::garbage_collect_task", "Garbage collection finished successfully!");
46 return Ok(())
47 }
48
49 while !txs.is_empty() {
50 for tx in txs {
52 let tx_hash = tx.hash();
53 let tx_vec = [tx.clone()];
54 let mut valid = false;
55
56 let mut forks = node.validator.consensus.forks.write().await;
58
59 for fork in forks.iter_mut() {
61 let overlay = match fork.overlay.lock().unwrap().full_clone() {
63 Ok(o) => o,
64 Err(e) => {
65 error!(
66 target: "darkfid::task::garbage_collect_task",
67 "Overlay full clone creation failed: {e}"
68 );
69 return Err(e)
70 }
71 };
72
73 let proposals_txs =
75 match overlay.lock().unwrap().get_blocks_txs_hashes(&fork.proposals) {
76 Ok(txs) => txs,
77 Err(e) => {
78 error!(
79 target: "darkfid::task::garbage_collect_task",
80 "Proposal transactions retrieval failed: {e}"
81 );
82 return Err(e)
83 }
84 };
85
86 if proposals_txs.contains(&tx_hash) {
88 continue
89 }
90
91 let next_block_height = match fork.get_next_block_height() {
93 Ok(h) => h,
94 Err(e) => {
95 error!(
96 target: "darkfid::task::garbage_collect_task",
97 "Next fork block height retrieval failed: {e}"
98 );
99 return Err(e)
100 }
101 };
102
103 let result = verify_transactions(
105 &overlay,
106 next_block_height,
107 node.validator.consensus.module.read().await.target,
108 &tx_vec,
109 &mut MerkleTree::new(1),
110 false,
111 )
112 .await;
113
114 match result {
116 Ok(_) => valid = true,
117 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {
118 fork.mempool.retain(|tx| *tx != tx_hash);
120 }
121 Err(e) => {
122 error!(
123 target: "darkfid::task::garbage_collect_task",
124 "Verifying transaction {tx_hash} failed: {e}"
125 );
126 return Err(e)
127 }
128 }
129 }
130
131 drop(forks);
133
134 if !valid {
136 debug!(target: "darkfid::task::garbage_collect_task", "Removing invalid transaction: {tx_hash}");
137 if let Err(e) = node.validator.blockchain.remove_pending_txs_hashes(&[tx_hash]) {
138 error!(
139 target: "darkfid::task::garbage_collect_task",
140 "Removing invalid transaction {tx_hash} failed: {e}"
141 );
142 };
143 }
144 }
145
146 (last_checked, txs) = match node
148 .validator
149 .blockchain
150 .transactions
151 .get_after_pending(last_checked + node.txs_batch_size as u64, node.txs_batch_size)
152 {
153 Ok(pair) => pair,
154 Err(e) => {
155 error!(
156 target: "darkfid::task::garbage_collect_task",
157 "Uproposed transactions next batch retrieval failed: {e}"
158 );
159 break
160 }
161 };
162 }
163
164 info!(target: "darkfid::task::garbage_collect_task", "Garbage collection finished successfully!");
165 Ok(())
166}
167
168pub async fn purge_unreferenced_trees(node: &DarkfiNodePtr) {
171 let submit_lock = node.registry.submit_lock.write().await;
173 let block_templates = node.registry.block_templates.write().await;
174 let jobs = node.registry.jobs.write().await;
175 let mm_jobs = node.registry.mm_jobs.write().await;
176
177 if let Err(e) = node
179 .validator
180 .consensus
181 .purge_unreferenced_trees(&mut node.registry.new_trees(&block_templates))
182 .await
183 {
184 error!(target: "darkfid::task::garbage_collect::purge_unreferenced_trees", "Purging unreferenced contract trees from the database failed: {e}");
185 }
186
187 drop(block_templates);
189 drop(jobs);
190 drop(mm_jobs);
191 drop(submit_lock);
192}