main.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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 std::{fs::File, io::Write};
  19. use clap::Parser;
  20. use darkfi::{
  21. blockchain::{
  22. block_store::{Block, BlockOrderStore, BlockProducer, BlockStore},
  23. header_store::{Header, HeaderStore},
  24. slot_store::SlotStore,
  25. tx_store::TxStore,
  26. Blockchain,
  27. },
  28. cli_desc,
  29. consensus::constants::EPOCH_LENGTH,
  30. tx::Transaction,
  31. util::{path::expand_path, time::Timestamp},
  32. Result,
  33. };
  34. use darkfi_sdk::crypto::MerkleNode;
  35. #[derive(Parser)]
  36. #[command(about = cli_desc!())]
  37. struct Args {
  38. #[arg(short, long, default_value = "../../../contrib/localnet/darkfid-single-node/")]
  39. /// Path containing the node folders
  40. path: String,
  41. #[arg(short, long, default_values = ["darkfid0", "faucetd"])]
  42. /// Node folder name (supports multiple values)
  43. node: Vec<String>,
  44. #[arg(short, long, default_value = "/blockchain/testnet")]
  45. /// Node blockchain folder
  46. blockchain: String,
  47. #[arg(short, long)]
  48. /// Export all contents into a JSON file
  49. export: bool,
  50. }
  51. #[derive(Debug)]
  52. struct BlockProducerInfo {
  53. _signature: String,
  54. _proposal: Transaction,
  55. }
  56. impl BlockProducerInfo {
  57. pub fn new(producer: &BlockProducer) -> BlockProducerInfo {
  58. let _signature = format!("{:?}", producer.signature);
  59. let _proposal = producer.proposal.clone();
  60. BlockProducerInfo { _signature, _proposal }
  61. }
  62. }
  63. #[derive(Debug)]
  64. struct HeaderInfo {
  65. _hash: blake3::Hash,
  66. _version: u8,
  67. _previous: blake3::Hash,
  68. _epoch: u64,
  69. _slot: u64,
  70. _timestamp: Timestamp,
  71. _root: MerkleNode,
  72. }
  73. impl HeaderInfo {
  74. pub fn new(_hash: blake3::Hash, header: &Header) -> HeaderInfo {
  75. let _version = header.version;
  76. let _previous = header.previous;
  77. let _epoch = header.epoch;
  78. let _slot = header.slot;
  79. let _timestamp = header.timestamp;
  80. let _root = header.root;
  81. HeaderInfo { _hash, _version, _previous, _epoch, _slot, _timestamp, _root }
  82. }
  83. }
  84. #[derive(Debug)]
  85. struct HeaderStoreInfo {
  86. _headers: Vec<HeaderInfo>,
  87. }
  88. impl HeaderStoreInfo {
  89. pub fn new(headerstore: &HeaderStore) -> HeaderStoreInfo {
  90. let mut _headers = Vec::new();
  91. let result = headerstore.get_all();
  92. match result {
  93. Ok(iter) => {
  94. for (hash, header) in iter.iter() {
  95. _headers.push(HeaderInfo::new(hash.clone(), &header));
  96. }
  97. }
  98. Err(e) => println!("Error: {:?}", e),
  99. }
  100. HeaderStoreInfo { _headers }
  101. }
  102. }
  103. #[derive(Debug)]
  104. struct BlockInfo {
  105. _hash: blake3::Hash,
  106. _magic: [u8; 4],
  107. _header: blake3::Hash,
  108. _txs: Vec<blake3::Hash>,
  109. _producer: BlockProducerInfo,
  110. _slots: Vec<u64>,
  111. }
  112. impl BlockInfo {
  113. pub fn new(_hash: blake3::Hash, block: &Block) -> BlockInfo {
  114. let _magic = block.magic;
  115. let _header = block.header;
  116. let _txs = block.txs.clone();
  117. let _producer = BlockProducerInfo::new(&block.producer);
  118. let _slots = block.slots.clone();
  119. BlockInfo { _hash, _magic, _header, _txs, _producer, _slots }
  120. }
  121. }
  122. #[derive(Debug)]
  123. struct BlockInfoChain {
  124. _blocks: Vec<BlockInfo>,
  125. }
  126. impl BlockInfoChain {
  127. pub fn new(blockstore: &BlockStore) -> BlockInfoChain {
  128. let mut _blocks = Vec::new();
  129. let result = blockstore.get_all();
  130. match result {
  131. Ok(iter) => {
  132. for (hash, block) in iter.iter() {
  133. _blocks.push(BlockInfo::new(hash.clone(), &block));
  134. }
  135. }
  136. Err(e) => println!("Error: {:?}", e),
  137. }
  138. BlockInfoChain { _blocks }
  139. }
  140. }
  141. #[derive(Debug)]
  142. struct OrderInfo {
  143. _slot: u64,
  144. _hash: blake3::Hash,
  145. }
  146. impl OrderInfo {
  147. pub fn new(_slot: u64, _hash: blake3::Hash) -> OrderInfo {
  148. OrderInfo { _slot, _hash }
  149. }
  150. }
  151. #[derive(Debug)]
  152. struct BlockOrderStoreInfo {
  153. _order: Vec<OrderInfo>,
  154. }
  155. impl BlockOrderStoreInfo {
  156. pub fn new(orderstore: &BlockOrderStore) -> BlockOrderStoreInfo {
  157. let mut _order = Vec::new();
  158. let result = orderstore.get_all();
  159. match result {
  160. Ok(iter) => {
  161. for (slot, hash) in iter.iter() {
  162. _order.push(OrderInfo::new(slot.clone(), hash.clone()));
  163. }
  164. }
  165. Err(e) => println!("Error: {:?}", e),
  166. }
  167. BlockOrderStoreInfo { _order }
  168. }
  169. }
  170. #[derive(Debug)]
  171. struct SlotInfo {
  172. _id: u64,
  173. _eta: String,
  174. _sigma1: String,
  175. _sigma2: String,
  176. }
  177. impl SlotInfo {
  178. pub fn new(_id: u64, _eta: String, _sigma1: String, _sigma2: String) -> SlotInfo {
  179. SlotInfo { _id, _eta, _sigma1, _sigma2 }
  180. }
  181. }
  182. #[derive(Debug)]
  183. struct SlotStoreInfo {
  184. _slots: Vec<SlotInfo>,
  185. }
  186. impl SlotStoreInfo {
  187. pub fn new(slot_store: &SlotStore) -> SlotStoreInfo {
  188. let mut _slots = Vec::new();
  189. let result = slot_store.get_all();
  190. match result {
  191. Ok(iter) => {
  192. for slot in iter.iter() {
  193. _slots.push(SlotInfo::new(
  194. slot.id,
  195. format!("{:?}", slot.previous_eta),
  196. format!("{:?}", slot.sigma1),
  197. format!("{:?}", slot.sigma2),
  198. ));
  199. }
  200. }
  201. Err(e) => println!("Error: {:?}", e),
  202. }
  203. SlotStoreInfo { _slots }
  204. }
  205. }
  206. #[derive(Debug)]
  207. struct TxInfo {
  208. _hash: blake3::Hash,
  209. _payload: Transaction,
  210. }
  211. impl TxInfo {
  212. pub fn new(_hash: blake3::Hash, tx: &Transaction) -> TxInfo {
  213. let _payload = tx.clone();
  214. TxInfo { _hash, _payload }
  215. }
  216. }
  217. #[derive(Debug)]
  218. struct TxStoreInfo {
  219. _transactions: Vec<TxInfo>,
  220. }
  221. impl TxStoreInfo {
  222. pub fn new(txstore: &TxStore) -> TxStoreInfo {
  223. let mut _transactions = Vec::new();
  224. let result = txstore.get_all();
  225. match result {
  226. Ok(iter) => {
  227. for (hash, tx) in iter.iter() {
  228. _transactions.push(TxInfo::new(hash.clone(), &tx));
  229. }
  230. }
  231. Err(e) => println!("Error: {:?}", e),
  232. }
  233. TxStoreInfo { _transactions }
  234. }
  235. }
  236. #[derive(Debug)]
  237. struct BlockchainInfo {
  238. _headers: HeaderStoreInfo,
  239. _blocks: BlockInfoChain,
  240. _order: BlockOrderStoreInfo,
  241. _slots: SlotStoreInfo,
  242. _transactions: TxStoreInfo,
  243. }
  244. impl BlockchainInfo {
  245. pub fn new(blockchain: &Blockchain) -> BlockchainInfo {
  246. let _headers = HeaderStoreInfo::new(&blockchain.headers);
  247. let _blocks = BlockInfoChain::new(&blockchain.blocks);
  248. let _order = BlockOrderStoreInfo::new(&blockchain.order);
  249. let _slots = SlotStoreInfo::new(&blockchain.slots);
  250. let _transactions = TxStoreInfo::new(&blockchain.transactions);
  251. BlockchainInfo { _headers, _blocks, _order, _slots, _transactions }
  252. }
  253. }
  254. fn statistics(folder: &str, node: &str, blockchain: &str) -> Result<()> {
  255. println!("Retrieving blockchain statistics for {node}...");
  256. // Node folder
  257. let folder = folder.to_owned() + node;
  258. // Initialize or load sled database
  259. let path = folder.to_owned() + blockchain;
  260. let db_path = expand_path(&path).unwrap();
  261. let sled_db = sled::open(&db_path)?;
  262. // Retrieve statistics
  263. let blockchain = Blockchain::new(&sled_db)?;
  264. let slot = blockchain.last_slot()?.id;
  265. let epoch = slot / EPOCH_LENGTH as u64;
  266. let (_, block) = blockchain.last()?;
  267. let blocks = blockchain.len();
  268. let txs = blockchain.txs_len();
  269. drop(sled_db);
  270. // Print statistics
  271. println!("Latest slot: {slot}");
  272. println!("Epoch: {epoch}");
  273. println!("Latest block: {block}");
  274. println!("Total blocks: {blocks}");
  275. println!("Total transactions: {txs}");
  276. Ok(())
  277. }
  278. fn export(folder: &str, node: &str, blockchain: &str) -> Result<()> {
  279. println!("Exporting data for {node}...");
  280. // Node folder
  281. let folder = folder.to_owned() + node;
  282. // Initialize or load sled database
  283. let path = folder.to_owned() + blockchain;
  284. let db_path = expand_path(&path).unwrap();
  285. let sled_db = sled::open(&db_path)?;
  286. // Data export
  287. let blockchain = Blockchain::new(&sled_db)?;
  288. let info = BlockchainInfo::new(&blockchain);
  289. let info_string = format!("{:#?}", info);
  290. let file_name = node.to_owned() + "_db";
  291. let mut file = File::create(file_name.clone())?;
  292. file.write(info_string.as_bytes())?;
  293. drop(sled_db);
  294. println!("Data exported to file: {file_name}");
  295. Ok(())
  296. }
  297. fn main() -> Result<()> {
  298. // Parse arguments
  299. let args = Args::parse();
  300. println!("Node folder path: {}", args.path);
  301. // Export data for each node
  302. for node in args.node {
  303. if args.export {
  304. export(&args.path, &node, &args.blockchain)?;
  305. continue
  306. }
  307. statistics(&args.path, &node, &args.blockchain)?;
  308. }
  309. Ok(())
  310. }