blocks.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. util::time::Timestamp,
  26. Error, Result,
  27. };
  28. use darkfi_sdk::crypto::schnorr::Signature;
  29. use crate::ExplorerService;
  30. #[derive(Debug, Clone)]
  31. /// Structure representing a block record.
  32. pub struct BlockRecord {
  33. /// Header hash identifier of the block
  34. pub header_hash: String,
  35. /// Block version
  36. pub version: u8,
  37. /// Previous block hash
  38. pub previous: String,
  39. /// Block height
  40. pub height: u32,
  41. /// Block creation timestamp
  42. pub timestamp: Timestamp,
  43. /// The block's nonce. This value changes arbitrarily with mining.
  44. pub nonce: u64,
  45. /// Merkle tree root of the transactions hashes contained in this block
  46. pub root: String,
  47. /// Block producer signature
  48. pub signature: Signature,
  49. }
  50. impl BlockRecord {
  51. /// Auxiliary function to convert a `BlockRecord` into a `JsonValue` array.
  52. pub fn to_json_array(&self) -> JsonValue {
  53. JsonValue::Array(vec![
  54. JsonValue::String(self.header_hash.clone()),
  55. JsonValue::Number(self.version as f64),
  56. JsonValue::String(self.previous.clone()),
  57. JsonValue::Number(self.height as f64),
  58. JsonValue::String(self.timestamp.to_string()),
  59. JsonValue::Number(self.nonce as f64),
  60. JsonValue::String(self.root.clone()),
  61. JsonValue::String(format!("{:?}", self.signature)),
  62. ])
  63. }
  64. }
  65. impl From<&BlockInfo> for BlockRecord {
  66. fn from(block: &BlockInfo) -> Self {
  67. Self {
  68. header_hash: block.hash().to_string(),
  69. version: block.header.version,
  70. previous: block.header.previous.to_string(),
  71. height: block.header.height,
  72. timestamp: block.header.timestamp,
  73. nonce: block.header.nonce,
  74. root: block.header.root.to_string(),
  75. signature: block.signature,
  76. }
  77. }
  78. }
  79. impl ExplorerService {
  80. /// Resets blocks in the database by clearing all block related trees, returning an Ok result on success.
  81. pub fn reset_blocks(&self) -> Result<()> {
  82. let db = &self.db.blockchain.sled_db;
  83. // Initialize block related trees to reset
  84. let trees_to_reset = [SLED_BLOCK_TREE, SLED_BLOCK_ORDER_TREE, SLED_BLOCK_DIFFICULTY_TREE];
  85. // Iterate over each tree and remove its entries
  86. for tree_name in &trees_to_reset {
  87. let tree = db.open_tree(tree_name)?;
  88. tree.clear()?;
  89. let tree_name_str = std::str::from_utf8(tree_name)?;
  90. info!(target: "blockchain-explorer::blocks", "Successfully reset block tree: {tree_name_str}");
  91. }
  92. Ok(())
  93. }
  94. /// Adds the provided [`BlockInfo`] to the block explorer database.
  95. ///
  96. /// This function processes each transaction in the block, calculating and updating the
  97. /// latest [`GasMetrics`] for non-genesis blocks and for transactions that are not
  98. /// PoW rewards. After processing all transactions, the block is permanently persisted to
  99. /// the explorer database.
  100. pub async fn put_block(&self, block: &BlockInfo) -> Result<()> {
  101. let blockchain_overlay = BlockchainOverlay::new(&self.db.blockchain)?;
  102. // Initialize collections to hold gas data and transactions that have gas data
  103. let mut tx_gas_data = Vec::with_capacity(block.txs.len());
  104. let mut txs_hashes_with_gas_data = Vec::with_capacity(block.txs.len());
  105. // Calculate gas data for non-PoW reward transactions and non-genesis blocks
  106. for (i, tx) in block.txs.iter().enumerate() {
  107. if !tx.is_pow_reward() && block.header.height != 0 {
  108. tx_gas_data.insert(i, self.calculate_tx_gas_data(tx, false).await?);
  109. txs_hashes_with_gas_data.insert(i, tx.hash());
  110. }
  111. }
  112. // If the block contains transaction gas data, insert the gas metrics into the metrics store
  113. if !tx_gas_data.is_empty() {
  114. self.db.metrics_store.insert_gas_metrics(
  115. block.header.height,
  116. &block.header.timestamp,
  117. &txs_hashes_with_gas_data,
  118. &tx_gas_data,
  119. )?;
  120. }
  121. // Add the block and commit the changes to persist it
  122. let _ = blockchain_overlay.lock().unwrap().add_block(block)?;
  123. blockchain_overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  124. debug!(target: "blockchain_explorer::blocks::put_block", "Added block {:?}", block);
  125. Ok(())
  126. }
  127. /// Provides the total block count.
  128. pub fn get_block_count(&self) -> usize {
  129. self.db.blockchain.len()
  130. }
  131. /// Fetch all known blocks from the database.
  132. pub fn get_blocks(&self) -> Result<Vec<BlockRecord>> {
  133. // Fetch blocks and handle any errors encountered
  134. let blocks = &self.db.blockchain.get_all().map_err(|e| {
  135. Error::DatabaseError(format!("[get_blocks] Block retrieval failed: {e:?}"))
  136. })?;
  137. // Transform the found blocks into a vector of block records
  138. let block_records: Vec<BlockRecord> = blocks.iter().map(BlockRecord::from).collect();
  139. Ok(block_records)
  140. }
  141. /// Fetch a block given its header hash from the database.
  142. pub fn get_block_by_hash(&self, header_hash: &str) -> Result<Option<BlockRecord>> {
  143. // Parse header hash, returning an error if parsing fails
  144. let header_hash = header_hash
  145. .parse::<HeaderHash>()
  146. .map_err(|_| Error::ParseFailed("[get_block_by_hash] Invalid header hash"))?;
  147. // Fetch block by hash and handle encountered errors
  148. match self.db.blockchain.get_blocks_by_hash(&[header_hash]) {
  149. Ok(blocks) => Ok(Some(BlockRecord::from(&blocks[0]))),
  150. Err(Error::BlockNotFound(_)) => Ok(None),
  151. Err(e) => Err(Error::DatabaseError(format!(
  152. "[get_block_by_hash] Block retrieval failed: {e:?}"
  153. ))),
  154. }
  155. }
  156. /// Fetch the last block from the database.
  157. pub fn last_block(&self) -> Result<Option<(u32, String)>> {
  158. let block_store = &self.db.blockchain.blocks;
  159. // Return None result when no blocks exist
  160. if block_store.is_empty() {
  161. return Ok(None);
  162. }
  163. // Blocks exist, retrieve last block
  164. let (height, header_hash) = block_store.get_last().map_err(|e| {
  165. Error::DatabaseError(format!("[last_block] Block retrieval failed: {e:?}"))
  166. })?;
  167. // Convert header hash to a string and return result
  168. Ok(Some((height, header_hash.to_string())))
  169. }
  170. /// Fetch the last N blocks from the database.
  171. pub fn get_last_n(&self, n: usize) -> Result<Vec<BlockRecord>> {
  172. // Fetch the last n blocks and handle any errors encountered
  173. let blocks_result = &self.db.blockchain.get_last_n(n).map_err(|e| {
  174. Error::DatabaseError(format!("[get_last_n] Block retrieval failed: {e:?}"))
  175. })?;
  176. // Transform the found blocks into a vector of block records
  177. let block_records: Vec<BlockRecord> = blocks_result.iter().map(BlockRecord::from).collect();
  178. Ok(block_records)
  179. }
  180. /// Fetch blocks within a specified range from the database.
  181. pub fn get_by_range(&self, start: u32, end: u32) -> Result<Vec<BlockRecord>> {
  182. // Fetch blocks in the specified range and handle any errors encountered
  183. let blocks_result = &self.db.blockchain.get_by_range(start, end).map_err(|e| {
  184. Error::DatabaseError(format!("[get_by_range]: Block retrieval failed: {e:?}"))
  185. })?;
  186. // Transform the found blocks into a vector of block records
  187. let block_records: Vec<BlockRecord> = blocks_result.iter().map(BlockRecord::from).collect();
  188. Ok(block_records)
  189. }
  190. }