Просмотр исходного кода

darkfid: protect reorg trees from getting dropped by gc

skoupidi 6 месяцев назад
Родитель
Сommit
95523adfcf

+ 8 - 3
bin/darkfid/src/task/consensus.rs

@@ -198,13 +198,18 @@ async fn consensus_task(
             error!(target: "darkfid", "Failed refreshing mining block templates: {e}")
             error!(target: "darkfid", "Failed refreshing mining block templates: {e}")
         }
         }
 
 
-        // Purge all unreferenced contract trees from the database
-        purge_unreferenced_trees(node).await;
-
         if confirmed.is_empty() {
         if confirmed.is_empty() {
             continue
             continue
         }
         }
 
 
+        // Purge all unreferenced contract trees from the database iff
+        // the node is not executing a reorg.
+        let reorg_lock = node.validator.synced.write().await;
+        if !*reorg_lock {
+            purge_unreferenced_trees(node).await;
+        }
+        drop(reorg_lock);
+
         let mut notif_blocks = Vec::with_capacity(confirmed.len());
         let mut notif_blocks = Vec::with_capacity(confirmed.len());
         for block in confirmed {
         for block in confirmed {
             notif_blocks.push(JsonValue::String(base64::encode(&serialize_async(&block).await)));
             notif_blocks.push(JsonValue::String(base64::encode(&serialize_async(&block).await)));

+ 9 - 8
bin/darkfid/src/task/sync.rs

@@ -210,14 +210,15 @@ async fn synced_peers(
 
 
             // Handle response
             // Handle response
             if response.synced {
             if response.synced {
-                // Grab response tip
-                let tip = if response.height.is_some() && response.hash.is_some() {
-                    (response.height.unwrap(), *response.hash.unwrap().inner())
-                } else {
-                    // Empty response while synced means the peer is on an
-                    // entirely different chain/fork, so we keep track of
-                    // them in the empty tip reference.
-                    (0, [0u8; 32])
+                // Grab response tip. Empty response while synced means
+                // the peer is on an entirely different chain/fork, so
+                // we keep track of them in the empty tip reference.
+                let tip = match response.height {
+                    Some(height) => match response.hash {
+                        Some(hash) => (height, *hash.inner()),
+                        None => (0, [0u8; 32]),
+                    },
+                    None => (0, [0u8; 32]),
                 };
                 };
                 let Some(tip_peers) = tips.get_mut(&tip) else {
                 let Some(tip_peers) = tips.get_mut(&tip) else {
                     tips.insert(tip, vec![peer.clone()]);
                     tips.insert(tip, vec![peer.clone()]);

+ 27 - 9
bin/darkfid/src/task/unknown_proposal.rs

@@ -471,7 +471,6 @@ async fn handle_reorg(
         (targets_rank == best_fork.targets_rank && hashes_rank <= best_fork.hashes_rank)
         (targets_rank == best_fork.targets_rank && hashes_rank <= best_fork.hashes_rank)
     {
     {
         info!(target: "darkfid::task::handle_reorg", "Peer sequence ranks lower than our current best fork, skipping...");
         info!(target: "darkfid::task::handle_reorg", "Peer sequence ranks lower than our current best fork, skipping...");
-        drop(forks);
         return true
         return true
     }
     }
     drop(forks);
     drop(forks);
@@ -482,12 +481,16 @@ async fn handle_reorg(
         return true
         return true
     };
     };
 
 
+    // Update the node reorg flag
+    *validator.reorg.write().await = true;
+
     // Create a fork from last common height
     // Create a fork from last common height
     let mut peer_fork =
     let mut peer_fork =
         match Fork::new(validator.consensus.blockchain.clone(), module.clone()).await {
         match Fork::new(validator.consensus.blockchain.clone(), module.clone()).await {
             Ok(f) => f,
             Ok(f) => f,
             Err(e) => {
             Err(e) => {
                 error!(target: "darkfid::task::handle_reorg", "Generating peer fork failed: {e}");
                 error!(target: "darkfid::task::handle_reorg", "Generating peer fork failed: {e}");
+                *validator.reorg.write().await = false;
                 return false
                 return false
             }
             }
         };
         };
@@ -503,14 +506,16 @@ async fn handle_reorg(
         Ok(i) => i,
         Ok(i) => i,
         Err(e) => {
         Err(e) => {
             error!(target: "darkfid::task::handle_reorg", "Retrieving state inverse diffs failed: {e}");
             error!(target: "darkfid::task::handle_reorg", "Retrieving state inverse diffs failed: {e}");
+            *validator.reorg.write().await = false;
             return false
             return false
         }
         }
     };
     };
     for inverse_diff in inverse_diffs.iter().rev() {
     for inverse_diff in inverse_diffs.iter().rev() {
-        if let Err(e) =
-            peer_fork.overlay.lock().unwrap().overlay.lock().unwrap().add_diff(inverse_diff)
-        {
+        let result =
+            peer_fork.overlay.lock().unwrap().overlay.lock().unwrap().add_diff(inverse_diff);
+        if let Err(e) = result {
             error!(target: "darkfid::task::handle_reorg", "Applying inverse diff failed: {e}");
             error!(target: "darkfid::task::handle_reorg", "Applying inverse diff failed: {e}");
+            *validator.reorg.write().await = false;
             return false
             return false
         }
         }
     }
     }
@@ -518,10 +523,12 @@ async fn handle_reorg(
     // Grab current overlay diff and use it as the first diff of the
     // Grab current overlay diff and use it as the first diff of the
     // peer fork, so all consecutive diffs represent just the proposal
     // peer fork, so all consecutive diffs represent just the proposal
     // changes.
     // changes.
-    let diff = match peer_fork.overlay.lock().unwrap().overlay.lock().unwrap().diff(&[]) {
+    let diff = peer_fork.overlay.lock().unwrap().overlay.lock().unwrap().diff(&[]);
+    let diff = match diff {
         Ok(d) => d,
         Ok(d) => d,
         Err(e) => {
         Err(e) => {
             error!(target: "darkfid::task::handle_reorg", "Generate full inverse diff failed: {e}");
             error!(target: "darkfid::task::handle_reorg", "Generate full inverse diff failed: {e}");
+            *validator.reorg.write().await = false;
             return false
             return false
         }
         }
     };
     };
@@ -544,6 +551,7 @@ async fn handle_reorg(
         let request = ForkProposalsRequest { headers: batch.clone(), fork_header: proposal.hash };
         let request = ForkProposalsRequest { headers: batch.clone(), fork_header: proposal.hash };
         if let Err(e) = channel.send(&request).await {
         if let Err(e) = channel.send(&request).await {
             debug!(target: "darkfid::task::handle_reorg", "Channel send failed: {e}");
             debug!(target: "darkfid::task::handle_reorg", "Channel send failed: {e}");
+            *validator.reorg.write().await = false;
             return true
             return true
         };
         };
 
 
@@ -555,6 +563,7 @@ async fn handle_reorg(
             Ok(r) => r,
             Ok(r) => r,
             Err(e) => {
             Err(e) => {
                 debug!(target: "darkfid::task::handle_reorg", "Asking peer for proposals sequence failed: {e}");
                 debug!(target: "darkfid::task::handle_reorg", "Asking peer for proposals sequence failed: {e}");
+                *validator.reorg.write().await = false;
                 return true
                 return true
             }
             }
         };
         };
@@ -563,6 +572,7 @@ async fn handle_reorg(
         // Response sequence must be the same length as the one requested
         // Response sequence must be the same length as the one requested
         if response.proposals.len() != batch.len() {
         if response.proposals.len() != batch.len() {
             debug!(target: "darkfid::task::handle_reorg", "Peer responded with a different proposals sequence length");
             debug!(target: "darkfid::task::handle_reorg", "Peer responded with a different proposals sequence length");
+            *validator.reorg.write().await = false;
             return true
             return true
         }
         }
 
 
@@ -573,6 +583,7 @@ async fn handle_reorg(
             // Validate its the proposal we requested
             // Validate its the proposal we requested
             if peer_proposal.hash != batch[peer_proposal_index] {
             if peer_proposal.hash != batch[peer_proposal_index] {
                 error!(target: "darkfid::task::handle_reorg", "Peer responded with a differend proposal: {} - {}", batch[peer_proposal_index], peer_proposal.hash);
                 error!(target: "darkfid::task::handle_reorg", "Peer responded with a differend proposal: {} - {}", batch[peer_proposal_index], peer_proposal.hash);
+                *validator.reorg.write().await = false;
                 return true
                 return true
             }
             }
 
 
@@ -581,12 +592,14 @@ async fn handle_reorg(
                 verify_fork_proposal(&mut peer_fork, peer_proposal, validator.verify_fees).await
                 verify_fork_proposal(&mut peer_fork, peer_proposal, validator.verify_fees).await
             {
             {
                 error!(target: "darkfid::task::handle_reorg", "Verify fork proposal failed: {e}");
                 error!(target: "darkfid::task::handle_reorg", "Verify fork proposal failed: {e}");
+                *validator.reorg.write().await = false;
                 return true
                 return true
             }
             }
 
 
             // Append proposal
             // Append proposal
             if let Err(e) = peer_fork.append_proposal(peer_proposal).await {
             if let Err(e) = peer_fork.append_proposal(peer_proposal).await {
                 error!(target: "darkfid::task::handle_reorg", "Appending proposal failed: {e}");
                 error!(target: "darkfid::task::handle_reorg", "Appending proposal failed: {e}");
+                *validator.reorg.write().await = false;
                 return true
                 return true
             }
             }
         }
         }
@@ -601,12 +614,14 @@ async fn handle_reorg(
     // Verify trigger proposal
     // Verify trigger proposal
     if let Err(e) = verify_fork_proposal(&mut peer_fork, proposal, validator.verify_fees).await {
     if let Err(e) = verify_fork_proposal(&mut peer_fork, proposal, validator.verify_fees).await {
         error!(target: "darkfid::task::handle_reorg", "Verify proposal failed: {e}");
         error!(target: "darkfid::task::handle_reorg", "Verify proposal failed: {e}");
+        *validator.reorg.write().await = false;
         return true
         return true
     }
     }
 
 
     // Append trigger proposal
     // Append trigger proposal
     if let Err(e) = peer_fork.append_proposal(proposal).await {
     if let Err(e) = peer_fork.append_proposal(proposal).await {
         error!(target: "darkfid::task::handle_reorg", "Appending proposal failed: {e}");
         error!(target: "darkfid::task::handle_reorg", "Appending proposal failed: {e}");
+        *validator.reorg.write().await = false;
         return true
         return true
     }
     }
 
 
@@ -616,6 +631,7 @@ async fn handle_reorg(
         Ok(i) => i,
         Ok(i) => i,
         Err(e) => {
         Err(e) => {
             debug!(target: "darkfid::task::handle_reorg", "Retrieving best fork index failed: {e}");
             debug!(target: "darkfid::task::handle_reorg", "Retrieving best fork index failed: {e}");
+            *validator.reorg.write().await = false;
             return false
             return false
         }
         }
     };
     };
@@ -625,26 +641,28 @@ async fn handle_reorg(
             peer_fork.hashes_rank <= best_fork.hashes_rank)
             peer_fork.hashes_rank <= best_fork.hashes_rank)
     {
     {
         info!(target: "darkfid::task::handle_reorg", "Peer fork ranks lower than our current best fork, skipping...");
         info!(target: "darkfid::task::handle_reorg", "Peer fork ranks lower than our current best fork, skipping...");
-        drop(forks);
+        *validator.reorg.write().await = false;
         return true
         return true
     }
     }
 
 
     // Execute the reorg
     // Execute the reorg
     info!(target: "darkfid::task::handle_reorg", "Peer fork ranks higher than our current best fork, executing reorg...");
     info!(target: "darkfid::task::handle_reorg", "Peer fork ranks higher than our current best fork, executing reorg...");
-    if let Err(e) = peer_fork
+    let result = peer_fork
         .overlay
         .overlay
         .lock()
         .lock()
         .unwrap()
         .unwrap()
         .overlay
         .overlay
         .lock()
         .lock()
         .unwrap()
         .unwrap()
-        .apply_diff(&peer_fork.diffs.remove(0))
-    {
+        .apply_diff(&peer_fork.diffs.remove(0));
+    if let Err(e) = result {
         error!(target: "darkfid::task::handle_reorg", "Applying full inverse diff failed: {e}");
         error!(target: "darkfid::task::handle_reorg", "Applying full inverse diff failed: {e}");
+        *validator.reorg.write().await = false;
         return false
         return false
     };
     };
     *validator.consensus.module.write().await = module;
     *validator.consensus.module.write().await = module;
     *forks = vec![peer_fork];
     *forks = vec![peer_fork];
+    *validator.reorg.write().await = false;
     drop(forks);
     drop(forks);
 
 
     // Check if we can confirm anything and broadcast them
     // Check if we can confirm anything and broadcast them

+ 4 - 1
src/validator/mod.rs

@@ -86,8 +86,10 @@ pub struct Validator {
     pub blockchain: Blockchain,
     pub blockchain: Blockchain,
     /// Hot/Live data used by the consensus algorithm
     /// Hot/Live data used by the consensus algorithm
     pub consensus: Consensus,
     pub consensus: Consensus,
-    /// Flag signalling node has finished initial sync
+    /// Flag signalling if the node is synced
     pub synced: RwLock<bool>,
     pub synced: RwLock<bool>,
+    /// Flag signalling if the node is trying to execute a reorg
+    pub reorg: RwLock<bool>,
     /// Flag to enable tx fee verification
     /// Flag to enable tx fee verification
     pub verify_fees: bool,
     pub verify_fees: bool,
 }
 }
@@ -133,6 +135,7 @@ impl Validator {
             blockchain,
             blockchain,
             consensus,
             consensus,
             synced: RwLock::new(false),
             synced: RwLock::new(false),
+            reorg: RwLock::new(false),
             verify_fees: config.verify_fees,
             verify_fees: config.verify_fees,
         });
         });