scanned_blocks.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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_serial::deserialize;
  19. use crate::{
  20. cache::CacheOverlay,
  21. dao::{SLED_MERKLE_TREES_DAO_DAOS, SLED_MERKLE_TREES_DAO_PROPOSALS},
  22. error::{WalletDbError, WalletDbResult},
  23. money::SLED_MERKLE_TREES_MONEY,
  24. Drk,
  25. };
  26. impl Drk {
  27. /// Get a scanned block information record.
  28. pub fn get_scanned_block(&self, height: &u32) -> WalletDbResult<(String, String)> {
  29. let Ok(query_result) = self.cache.scanned_blocks.get(height.to_be_bytes()) else {
  30. return Err(WalletDbError::QueryExecutionFailed);
  31. };
  32. let Some(value_bytes) = query_result else {
  33. return Err(WalletDbError::RowNotFound);
  34. };
  35. let Ok((hash, signing_key)) = deserialize(&value_bytes) else {
  36. return Err(WalletDbError::ParseColumnValueError);
  37. };
  38. Ok((hash, signing_key))
  39. }
  40. /// Fetch all scanned block information records.
  41. pub fn get_scanned_block_records(&self) -> WalletDbResult<Vec<(u32, String, String)>> {
  42. let mut scanned_blocks = vec![];
  43. for record in self.cache.scanned_blocks.iter() {
  44. let Ok((key, value)) = record else {
  45. return Err(WalletDbError::QueryExecutionFailed);
  46. };
  47. let key: [u8; 4] = match key.as_ref().try_into() {
  48. Ok(k) => k,
  49. Err(_) => return Err(WalletDbError::ParseColumnValueError),
  50. };
  51. let key = u32::from_be_bytes(key);
  52. let Ok((hash, signing_key)) = deserialize(&value) else {
  53. return Err(WalletDbError::ParseColumnValueError);
  54. };
  55. scanned_blocks.push((key, hash, signing_key));
  56. }
  57. Ok(scanned_blocks)
  58. }
  59. /// Get the last scanned block height and hash from the wallet.
  60. /// If database is empty default (0, '-') is returned.
  61. pub fn get_last_scanned_block(&self) -> WalletDbResult<(u32, String)> {
  62. let Ok(query_result) = self.cache.scanned_blocks.last() else {
  63. return Err(WalletDbError::QueryExecutionFailed);
  64. };
  65. let Some((key, value)) = query_result else { return Ok((0, String::from("-"))) };
  66. let key: [u8; 4] = match key.as_ref().try_into() {
  67. Ok(k) => k,
  68. Err(_) => return Err(WalletDbError::ParseColumnValueError),
  69. };
  70. let key = u32::from_be_bytes(key);
  71. let Ok((hash, _)) = deserialize::<(String, String)>(&value) else {
  72. return Err(WalletDbError::ParseColumnValueError);
  73. };
  74. Ok((key, hash))
  75. }
  76. /// Reset the scanned blocks information records in the cache.
  77. pub fn reset_scanned_blocks(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
  78. output.push(String::from("Resetting scanned blocks"));
  79. if let Err(e) = self.cache.scanned_blocks.clear() {
  80. output
  81. .push(format!("[reset_scanned_blocks] Resetting scanned blocks tree failed: {e}"));
  82. return Err(WalletDbError::GenericError)
  83. }
  84. if let Err(e) = self.cache.state_inverse_diff.clear() {
  85. output.push(format!(
  86. "[reset_scanned_blocks] Resetting state inverse diffs tree failed: {e}"
  87. ));
  88. return Err(WalletDbError::GenericError)
  89. }
  90. output.push(String::from("Successfully reset scanned blocks"));
  91. Ok(())
  92. }
  93. /// Reset state to provided block height.
  94. /// If genesis block height(0) was provided, perform a full reset.
  95. pub async fn reset_to_height(
  96. &self,
  97. height: u32,
  98. output: &mut Vec<String>,
  99. ) -> WalletDbResult<()> {
  100. output.push(format!("Resetting wallet state to block: {height}"));
  101. // If genesis block height(0) was provided,
  102. // perform a full reset.
  103. if height == 0 {
  104. return self.reset(output)
  105. }
  106. // Grab last scanned block height
  107. let (last, _) = self.get_last_scanned_block()?;
  108. // Check if requested height is after it
  109. if last <= height {
  110. output.push(String::from(
  111. "Requested block height is greater or equal to last scanned block",
  112. ));
  113. return Ok(())
  114. }
  115. // Grab our current merkle trees
  116. let mut money_tree = match self.get_money_tree().await {
  117. Ok(t) => t,
  118. Err(e) => {
  119. output.push(format!("[reset_to_height] Money merkle tree retrieval failed: {e}"));
  120. return Err(WalletDbError::GenericError)
  121. }
  122. };
  123. let (mut dao_daos_tree, mut dao_proposals_tree) = match self.get_dao_trees().await {
  124. Ok(p) => p,
  125. Err(e) => {
  126. output.push(format!("[reset_to_height] DAO merkle trees retrieval failed: {e}"));
  127. return Err(WalletDbError::GenericError)
  128. }
  129. };
  130. // Create an overlay to apply the reverse diffs
  131. let mut overlay = match CacheOverlay::new(&self.cache) {
  132. Ok(o) => o,
  133. Err(e) => {
  134. output.push(format!("[reset_to_height] Creating cache overlay failed: {e}"));
  135. return Err(WalletDbError::GenericError)
  136. }
  137. };
  138. // Grab all state inverse diffs until requested height,
  139. // going backwards.
  140. for height in (height + 1..=last).rev() {
  141. let inverse_diff = match self.cache.get_state_inverse_diff(&height) {
  142. Ok(d) => d,
  143. Err(e) => {
  144. output.push(format!(
  145. "[reset_to_height] Retrieving state inverse diff from cache failed: {e}"
  146. ));
  147. return Err(WalletDbError::GenericError)
  148. }
  149. };
  150. // Apply it
  151. if let Err(e) = overlay.0.add_diff(&inverse_diff) {
  152. output.push(format!(
  153. "[reset_to_height] Adding state inverse diff to the cache overlay failed: {e}"
  154. ));
  155. return Err(WalletDbError::GenericError)
  156. }
  157. if let Err(e) = overlay.0.apply_diff(&inverse_diff) {
  158. output.push(format!("[reset_to_height] Applying state inverse diff to the cache overlay failed: {e}"));
  159. return Err(WalletDbError::GenericError)
  160. }
  161. // Remove it
  162. if let Err(e) = self.cache.state_inverse_diff.remove(height.to_be_bytes()) {
  163. output.push(format!(
  164. "[reset_to_height] Removing state inverse diff from the cache failed: {e}"
  165. ));
  166. return Err(WalletDbError::GenericError)
  167. }
  168. // Rewind and update the merkle trees
  169. money_tree.rewind();
  170. dao_daos_tree.rewind();
  171. dao_proposals_tree.rewind();
  172. if let Err(e) = self.cache.insert_merkle_trees(&[
  173. (SLED_MERKLE_TREES_MONEY, &money_tree),
  174. (SLED_MERKLE_TREES_DAO_DAOS, &dao_daos_tree),
  175. (SLED_MERKLE_TREES_DAO_PROPOSALS, &dao_proposals_tree),
  176. ]) {
  177. output.push(format!("[reset_to_height] Updating merkle trees failed: {e}"));
  178. return Err(WalletDbError::GenericError)
  179. };
  180. // Flush sled
  181. if let Err(e) = self.cache.sled_db.flush() {
  182. output.push(format!("[reset_to_height] Flushing cache sled database failed: {e}"));
  183. return Err(WalletDbError::GenericError)
  184. }
  185. }
  186. // Remove all wallet coins created after the reset height
  187. self.remove_money_coins_after(&height, output)?;
  188. // Unspent all wallet coins spent after the reset height
  189. self.unspent_money_coins_after(&height, output)?;
  190. // Unfreeze tokens mint authorities frozen after the reset
  191. // height.
  192. self.unfreeze_mint_authorities_after(&height, output)?;
  193. // Unconfirm DAOs minted after the reset height
  194. self.unconfirm_daos_after(&height, output)?;
  195. // Unconfirm DAOs proposals minted after the reset height
  196. self.unconfirm_dao_proposals_after(&height, output)?;
  197. // Reset execution information for DAOs proposals executed
  198. // after the reset height.
  199. self.unexec_dao_proposals_after(&height, output)?;
  200. // Remove all DAOs proposals votes created after the reset
  201. // height.
  202. self.remove_dao_votes_after(&height, output)?;
  203. // Unlock all contracts frozen after the reset height
  204. self.unlock_deploy_authorities_after(&height, output)?;
  205. // Remove all contracts history records created after the reset
  206. // height.
  207. self.remove_deploy_history_after(&height, output)?;
  208. // Set reverted status to all transactions executed after reset
  209. // height.
  210. self.revert_transactions_after(&height, output)?;
  211. output.push(String::from("Successfully reset wallet state"));
  212. Ok(())
  213. }
  214. }