blocks.rs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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 log::{debug, info};
  19. use tinyjson::JsonValue;
  20. use darkfi::{
  21. blockchain::{
  22. BlockInfo, BlockchainOverlay, HeaderHash, SLED_BLOCK_DIFFICULTY_TREE,
  23. SLED_BLOCK_ORDER_TREE, SLED_BLOCK_TREE,
  24. },
  25. Error, Result,
  26. };
  27. use darkfi_sdk::crypto::schnorr::Signature;
  28. use crate::ExplorerDb;
  29. #[derive(Debug, Clone)]
  30. /// Structure representing a block record.
  31. pub struct BlockRecord {
  32. /// Header hash identifier of the block
  33. pub header_hash: String,
  34. /// Block version
  35. pub version: u8,
  36. /// Previous block hash
  37. pub previous: String,
  38. /// Block height
  39. pub height: u32,
  40. /// Block creation timestamp
  41. pub timestamp: u64,
  42. /// The block's nonce. This value changes arbitrarily with mining.
  43. pub nonce: u64,
  44. /// Merkle tree root of the transactions hashes contained in this block
  45. pub root: String,
  46. /// Block producer signature
  47. pub signature: Signature,
  48. }
  49. impl BlockRecord {
  50. /// Auxiliary function to convert a `BlockRecord` into a `JsonValue` array.
  51. pub fn to_json_array(&self) -> JsonValue {
  52. JsonValue::Array(vec![
  53. JsonValue::String(self.header_hash.clone()),
  54. JsonValue::Number(self.version as f64),
  55. JsonValue::String(self.previous.clone()),
  56. JsonValue::Number(self.height as f64),
  57. JsonValue::Number(self.timestamp as f64),
  58. JsonValue::Number(self.nonce as f64),
  59. JsonValue::String(self.root.clone()),
  60. JsonValue::String(format!("{:?}", self.signature)),
  61. ])
  62. }
  63. }
  64. impl From<&BlockInfo> for BlockRecord {
  65. fn from(block: &BlockInfo) -> Self {
  66. Self {
  67. header_hash: block.hash().to_string(),
  68. version: block.header.version,
  69. previous: block.header.previous.to_string(),
  70. height: block.header.height,
  71. timestamp: block.header.timestamp.inner(),
  72. nonce: block.header.nonce,
  73. root: block.header.root.to_string(),
  74. signature: block.signature,
  75. }
  76. }
  77. }
  78. impl ExplorerDb {
  79. /// Resets blocks in the database by clearing all block related trees, returning an Ok result on success.
  80. pub fn reset_blocks(&self) -> Result<()> {
  81. let db = &self.blockchain.sled_db;
  82. // Initialize block related trees to reset
  83. let trees_to_reset = [SLED_BLOCK_TREE, SLED_BLOCK_ORDER_TREE, SLED_BLOCK_DIFFICULTY_TREE];
  84. // Iterate over each tree and remove its entries
  85. for tree_name in &trees_to_reset {
  86. let tree = db.open_tree(tree_name)?;
  87. tree.clear()?;
  88. let tree_name_str = std::str::from_utf8(tree_name)?;
  89. info!(target: "blockchain-explorer::blocks", "Successfully reset block tree: {tree_name_str}");
  90. }
  91. Ok(())
  92. }
  93. /// Adds a block to the block explorer database.
  94. pub async fn put_block(&self, block: &BlockInfo) -> Result<()> {
  95. let blockchain_overlay = BlockchainOverlay::new(&self.blockchain)?;
  96. // Add the synced block and commit the changes
  97. let _ = blockchain_overlay.lock().unwrap().add_block(block)?;
  98. blockchain_overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  99. debug!(target:"blockchain_explorer::blocks::put_block", "Added block {:?}", block);
  100. Ok(())
  101. }
  102. /// Provides the total block count.
  103. pub fn get_block_count(&self) -> usize {
  104. self.blockchain.len()
  105. }
  106. /// Fetch all known blocks from the database.
  107. pub fn get_blocks(&self) -> Result<Vec<BlockRecord>> {
  108. // Fetch blocks and handle any errors encountered
  109. let blocks = &self.blockchain.get_all().map_err(|e| {
  110. Error::DatabaseError(format!("[get_blocks] Block retrieval failed: {e:?}"))
  111. })?;
  112. // Transform the found blocks into a vector of block records
  113. let block_records: Vec<BlockRecord> = blocks.iter().map(BlockRecord::from).collect();
  114. Ok(block_records)
  115. }
  116. /// Fetch a block given its header hash from the database.
  117. pub fn get_block_by_hash(&self, header_hash: &str) -> Result<Option<BlockRecord>> {
  118. // Parse header hash, returning an error if parsing fails
  119. let header_hash = header_hash
  120. .parse::<HeaderHash>()
  121. .map_err(|_| Error::ParseFailed("[get_block_by_hash] Invalid header hash"))?;
  122. // Fetch block by hash and handle encountered errors
  123. match self.blockchain.get_blocks_by_hash(&[header_hash]) {
  124. Ok(blocks) => Ok(Some(BlockRecord::from(&blocks[0]))),
  125. Err(Error::BlockNotFound(_)) => Ok(None),
  126. Err(e) => Err(Error::DatabaseError(format!(
  127. "[get_block_by_hash] Block retrieval failed: {e:?}"
  128. ))),
  129. }
  130. }
  131. /// Fetch the last block from the database.
  132. pub fn last_block(&self) -> Result<Option<(u32, String)>> {
  133. let block_store = &self.blockchain.blocks;
  134. // Return None result when no blocks exist
  135. if block_store.is_empty() {
  136. return Ok(None);
  137. }
  138. // Blocks exist, retrieve last block
  139. let (height, header_hash) = block_store.get_last().map_err(|e| {
  140. Error::DatabaseError(format!("[last_block] Block retrieval failed: {e:?}"))
  141. })?;
  142. // Convert header hash to a string and return result
  143. Ok(Some((height, header_hash.to_string())))
  144. }
  145. /// Fetch the last N blocks from the database.
  146. pub fn get_last_n(&self, n: usize) -> Result<Vec<BlockRecord>> {
  147. // Fetch the last n blocks and handle any errors encountered
  148. let blocks_result = &self.blockchain.get_last_n(n).map_err(|e| {
  149. Error::DatabaseError(format!("[get_last_n] Block retrieval failed: {e:?}"))
  150. })?;
  151. // Transform the found blocks into a vector of block records
  152. let block_records: Vec<BlockRecord> = blocks_result.iter().map(BlockRecord::from).collect();
  153. Ok(block_records)
  154. }
  155. /// Fetch blocks within a specified range from the database.
  156. pub fn get_by_range(&self, start: u32, end: u32) -> Result<Vec<BlockRecord>> {
  157. // Fetch blocks in the specified range and handle any errors encountered
  158. let blocks_result = &self.blockchain.get_by_range(start, end).map_err(|e| {
  159. Error::DatabaseError(format!("[get_by_range]: Block retrieval failed: {e:?}"))
  160. })?;
  161. // Transform the found blocks into a vector of block records
  162. let block_records: Vec<BlockRecord> = blocks_result.iter().map(BlockRecord::from).collect();
  163. Ok(block_records)
  164. }
  165. }