statistics.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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 rusqlite::types::Value;
  19. use tinyjson::JsonValue;
  20. use darkfi_sdk::blockchain::block_epoch;
  21. use drk::error::{WalletDbError, WalletDbResult};
  22. use crate::{blocks::BLOCKS_TABLE, transactions::TRANSACTIONS_TABLE, BlockchainExplorer};
  23. #[derive(Debug, Clone)]
  24. /// Structure representing basic statistic extracted from the database.
  25. pub struct BaseStatistics {
  26. /// Current blockchain height
  27. pub height: u32,
  28. /// Current blockchain epoch (based on current height)
  29. pub epoch: u8,
  30. /// Blockchains' last block hash
  31. pub last_block: String,
  32. /// Blockchain total blocks
  33. pub total_blocks: u64,
  34. /// Blockchain total transactions
  35. pub total_txs: u64,
  36. }
  37. impl BaseStatistics {
  38. /// Auxiliary function to convert `BaseStatistics` into a `JsonValue` array.
  39. pub fn to_json_array(&self) -> JsonValue {
  40. JsonValue::Array(vec![
  41. JsonValue::Number(self.height as f64),
  42. JsonValue::Number(self.epoch as f64),
  43. JsonValue::String(self.last_block.clone()),
  44. JsonValue::Number(self.total_blocks as f64),
  45. JsonValue::Number(self.total_txs as f64),
  46. ])
  47. }
  48. }
  49. impl BlockchainExplorer {
  50. /// Fetch total rows count of given table from the database.
  51. pub async fn get_table_count(&self, table: &str) -> WalletDbResult<u64> {
  52. // First we prepare the query
  53. let query = format!("SELECT COUNT() FROM {};", table);
  54. let Ok(conn) = self.database.conn.lock() else {
  55. return Err(WalletDbError::FailedToAquireLock)
  56. };
  57. let Ok(mut stmt) = conn.prepare(&query) else {
  58. return Err(WalletDbError::QueryPreparationFailed)
  59. };
  60. // Execute the query using provided params
  61. let Ok(mut rows) = stmt.query([]) else { return Err(WalletDbError::QueryExecutionFailed) };
  62. // Check if row exists
  63. let Ok(next) = rows.next() else { return Err(WalletDbError::QueryExecutionFailed) };
  64. let row = match next {
  65. Some(row_result) => row_result,
  66. None => return Ok(0_u64),
  67. };
  68. // Parse returned value
  69. let Ok(count) = row.get(0) else { return Err(WalletDbError::ParseColumnValueError) };
  70. let Value::Integer(count) = count else { return Err(WalletDbError::ParseColumnValueError) };
  71. let Ok(count) = u64::try_from(count) else {
  72. return Err(WalletDbError::ParseColumnValueError)
  73. };
  74. Ok(count)
  75. }
  76. /// Fetch current database basic statistic.
  77. pub async fn get_base_statistics(&self) -> WalletDbResult<BaseStatistics> {
  78. let (height, last_block) = self.last_block().await?;
  79. let epoch = block_epoch(height);
  80. let total_blocks = self.get_table_count(BLOCKS_TABLE).await?;
  81. let total_txs = self.get_table_count(TRANSACTIONS_TABLE).await?;
  82. Ok(BaseStatistics { height, epoch, last_block, total_blocks, total_txs })
  83. }
  84. }