main.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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 std::{fs::File, io::Write};
  19. use clap::Parser;
  20. use darkfi::{
  21. blockchain::{
  22. block_store::{
  23. Block, BlockDifficulty, BlockDifficultyStore, BlockOrderStore, BlockRanks, BlockStore,
  24. },
  25. contract_store::{ContractStateStore, WasmStore},
  26. header_store::{Header, HeaderStore},
  27. tx_store::{PendingTxOrderStore, PendingTxStore, TxStore},
  28. Blockchain,
  29. },
  30. cli_desc,
  31. tx::Transaction,
  32. util::{path::expand_path, time::Timestamp},
  33. Result,
  34. };
  35. use darkfi_sdk::{
  36. blockchain::block_epoch,
  37. crypto::{ContractId, MerkleTree},
  38. };
  39. use num_bigint::BigUint;
  40. #[derive(Parser)]
  41. #[command(about = cli_desc!())]
  42. struct Args {
  43. #[arg(short, long, default_value = "../../../contrib/localnet/darkfid-single-node/")]
  44. /// Path containing the node folders
  45. path: String,
  46. #[arg(short, long, default_values = ["darkfid"])]
  47. /// Node folder name (supports multiple values)
  48. node: Vec<String>,
  49. #[arg(short, long, default_value = "")]
  50. /// Node blockchain folder
  51. blockchain: String,
  52. #[arg(short, long)]
  53. /// Export all contents into a JSON file
  54. export: bool,
  55. }
  56. #[derive(Debug)]
  57. struct HeaderInfo {
  58. _hash: blake3::Hash,
  59. _version: u8,
  60. _previous: blake3::Hash,
  61. _height: u64,
  62. _timestamp: Timestamp,
  63. _nonce: u64,
  64. _tree: MerkleTree,
  65. }
  66. impl HeaderInfo {
  67. pub fn new(_hash: blake3::Hash, header: &Header) -> HeaderInfo {
  68. HeaderInfo {
  69. _hash,
  70. _version: header.version,
  71. _previous: header.previous,
  72. _height: header.height,
  73. _timestamp: header.timestamp,
  74. _nonce: header.nonce,
  75. _tree: header.tree.clone(),
  76. }
  77. }
  78. }
  79. #[derive(Debug)]
  80. struct HeaderStoreInfo {
  81. _headers: Vec<HeaderInfo>,
  82. }
  83. impl HeaderStoreInfo {
  84. pub fn new(headerstore: &HeaderStore) -> HeaderStoreInfo {
  85. let mut _headers = Vec::new();
  86. let result = headerstore.get_all();
  87. match result {
  88. Ok(iter) => {
  89. for (hash, header) in iter.iter() {
  90. _headers.push(HeaderInfo::new(*hash, header));
  91. }
  92. }
  93. Err(e) => println!("Error: {:?}", e),
  94. }
  95. HeaderStoreInfo { _headers }
  96. }
  97. }
  98. #[derive(Debug)]
  99. struct BlockInfo {
  100. _hash: blake3::Hash,
  101. _header: blake3::Hash,
  102. _txs: Vec<blake3::Hash>,
  103. _signature: String,
  104. }
  105. impl BlockInfo {
  106. pub fn new(_hash: blake3::Hash, block: &Block) -> BlockInfo {
  107. BlockInfo {
  108. _hash,
  109. _header: block.header,
  110. _txs: block.txs.clone(),
  111. _signature: format!("{:?}", block.signature),
  112. }
  113. }
  114. }
  115. #[derive(Debug)]
  116. struct BlockInfoChain {
  117. _blocks: Vec<BlockInfo>,
  118. }
  119. impl BlockInfoChain {
  120. pub fn new(blockstore: &BlockStore) -> BlockInfoChain {
  121. let mut _blocks = Vec::new();
  122. let result = blockstore.get_all();
  123. match result {
  124. Ok(iter) => {
  125. for (hash, block) in iter.iter() {
  126. _blocks.push(BlockInfo::new(*hash, block));
  127. }
  128. }
  129. Err(e) => println!("Error: {:?}", e),
  130. }
  131. BlockInfoChain { _blocks }
  132. }
  133. }
  134. #[derive(Debug)]
  135. struct OrderInfo {
  136. _height: u64,
  137. _hash: blake3::Hash,
  138. }
  139. impl OrderInfo {
  140. pub fn new(_height: u64, _hash: blake3::Hash) -> OrderInfo {
  141. OrderInfo { _height, _hash }
  142. }
  143. }
  144. #[derive(Debug)]
  145. struct BlockOrderStoreInfo {
  146. _order: Vec<OrderInfo>,
  147. }
  148. impl BlockOrderStoreInfo {
  149. pub fn new(orderstore: &BlockOrderStore) -> BlockOrderStoreInfo {
  150. let mut _order = Vec::new();
  151. let result = orderstore.get_all();
  152. match result {
  153. Ok(iter) => {
  154. for (height, hash) in iter.iter() {
  155. _order.push(OrderInfo::new(*height, *hash));
  156. }
  157. }
  158. Err(e) => println!("Error: {:?}", e),
  159. }
  160. BlockOrderStoreInfo { _order }
  161. }
  162. }
  163. #[derive(Debug)]
  164. struct BlockRanksInfo {
  165. _target_rank: BigUint,
  166. _targets_rank: BigUint,
  167. _hash_rank: BigUint,
  168. _hashes_rank: BigUint,
  169. }
  170. impl BlockRanksInfo {
  171. pub fn new(ranks: &BlockRanks) -> BlockRanksInfo {
  172. BlockRanksInfo {
  173. _target_rank: ranks.target_rank.clone(),
  174. _targets_rank: ranks.targets_rank.clone(),
  175. _hash_rank: ranks.hash_rank.clone(),
  176. _hashes_rank: ranks.hashes_rank.clone(),
  177. }
  178. }
  179. }
  180. #[derive(Debug)]
  181. struct BlockDifficultyInfo {
  182. _height: u64,
  183. _timestamp: Timestamp,
  184. _difficulty: BigUint,
  185. _cummulative_difficulty: BigUint,
  186. _ranks: BlockRanksInfo,
  187. }
  188. impl BlockDifficultyInfo {
  189. pub fn new(difficulty: &BlockDifficulty) -> BlockDifficultyInfo {
  190. BlockDifficultyInfo {
  191. _height: difficulty.height,
  192. _timestamp: difficulty.timestamp,
  193. _difficulty: difficulty.difficulty.clone(),
  194. _cummulative_difficulty: difficulty.cummulative_difficulty.clone(),
  195. _ranks: BlockRanksInfo::new(&difficulty.ranks),
  196. }
  197. }
  198. }
  199. #[derive(Debug)]
  200. struct BlockDifficultyStoreInfo {
  201. _difficulties: Vec<BlockDifficultyInfo>,
  202. }
  203. impl BlockDifficultyStoreInfo {
  204. pub fn new(difficultiesstore: &BlockDifficultyStore) -> BlockDifficultyStoreInfo {
  205. let mut _difficulties = Vec::new();
  206. let result = difficultiesstore.get_all();
  207. match result {
  208. Ok(iter) => {
  209. for (_, difficulty) in iter.iter() {
  210. _difficulties.push(BlockDifficultyInfo::new(difficulty));
  211. }
  212. }
  213. Err(e) => println!("Error: {:?}", e),
  214. }
  215. BlockDifficultyStoreInfo { _difficulties }
  216. }
  217. }
  218. #[derive(Debug)]
  219. struct TxInfo {
  220. _hash: blake3::Hash,
  221. _payload: Transaction,
  222. }
  223. impl TxInfo {
  224. pub fn new(_hash: blake3::Hash, tx: &Transaction) -> TxInfo {
  225. TxInfo { _hash, _payload: tx.clone() }
  226. }
  227. }
  228. #[derive(Debug)]
  229. struct TxStoreInfo {
  230. _transactions: Vec<TxInfo>,
  231. }
  232. impl TxStoreInfo {
  233. pub fn new(txstore: &TxStore) -> TxStoreInfo {
  234. let mut _transactions = Vec::new();
  235. let result = txstore.get_all();
  236. match result {
  237. Ok(iter) => {
  238. for (hash, tx) in iter.iter() {
  239. _transactions.push(TxInfo::new(*hash, tx));
  240. }
  241. }
  242. Err(e) => println!("Error: {:?}", e),
  243. }
  244. TxStoreInfo { _transactions }
  245. }
  246. }
  247. #[derive(Debug)]
  248. struct PendingTxStoreInfo {
  249. _transactions: Vec<TxInfo>,
  250. }
  251. impl PendingTxStoreInfo {
  252. pub fn new(pendingtxstore: &PendingTxStore) -> PendingTxStoreInfo {
  253. let mut _transactions = Vec::new();
  254. let result = pendingtxstore.get_all();
  255. match result {
  256. Ok(iter) => {
  257. for (hash, tx) in iter.iter() {
  258. _transactions.push(TxInfo::new(*hash, tx));
  259. }
  260. }
  261. Err(e) => println!("Error: {:?}", e),
  262. }
  263. PendingTxStoreInfo { _transactions }
  264. }
  265. }
  266. #[derive(Debug)]
  267. struct PendingTxOrderStoreInfo {
  268. _order: Vec<OrderInfo>,
  269. }
  270. impl PendingTxOrderStoreInfo {
  271. pub fn new(orderstore: &PendingTxOrderStore) -> PendingTxOrderStoreInfo {
  272. let mut _order = Vec::new();
  273. let result = orderstore.get_all();
  274. match result {
  275. Ok(iter) => {
  276. for (height, hash) in iter.iter() {
  277. _order.push(OrderInfo::new(*height, *hash));
  278. }
  279. }
  280. Err(e) => println!("Error: {:?}", e),
  281. }
  282. PendingTxOrderStoreInfo { _order }
  283. }
  284. }
  285. #[derive(Debug)]
  286. struct ContractStateInfo {
  287. _id: ContractId,
  288. _state_hashes: Vec<blake3::Hash>,
  289. }
  290. impl ContractStateInfo {
  291. pub fn new(_id: ContractId, state_hashes: &[blake3::Hash]) -> ContractStateInfo {
  292. ContractStateInfo { _id, _state_hashes: state_hashes.to_vec() }
  293. }
  294. }
  295. #[derive(Debug)]
  296. struct ContractStateStoreInfo {
  297. _contracts: Vec<ContractStateInfo>,
  298. }
  299. impl ContractStateStoreInfo {
  300. pub fn new(contractsstore: &ContractStateStore) -> ContractStateStoreInfo {
  301. let mut _contracts = Vec::new();
  302. let result = contractsstore.get_all();
  303. match result {
  304. Ok(iter) => {
  305. for (id, state_hash) in iter.iter() {
  306. _contracts.push(ContractStateInfo::new(*id, state_hash));
  307. }
  308. }
  309. Err(e) => println!("Error: {:?}", e),
  310. }
  311. ContractStateStoreInfo { _contracts }
  312. }
  313. }
  314. #[derive(Debug)]
  315. struct WasmInfo {
  316. _id: ContractId,
  317. _bincode_hash: blake3::Hash,
  318. }
  319. impl WasmInfo {
  320. pub fn new(_id: ContractId, bincode: &[u8]) -> WasmInfo {
  321. let _bincode_hash = blake3::hash(bincode);
  322. WasmInfo { _id, _bincode_hash }
  323. }
  324. }
  325. #[derive(Debug)]
  326. struct WasmStoreInfo {
  327. _wasm_bincodes: Vec<WasmInfo>,
  328. }
  329. impl WasmStoreInfo {
  330. pub fn new(wasmstore: &WasmStore) -> WasmStoreInfo {
  331. let mut _wasm_bincodes = Vec::new();
  332. let result = wasmstore.get_all();
  333. match result {
  334. Ok(iter) => {
  335. for (id, bincode) in iter.iter() {
  336. _wasm_bincodes.push(WasmInfo::new(*id, bincode));
  337. }
  338. }
  339. Err(e) => println!("Error: {:?}", e),
  340. }
  341. WasmStoreInfo { _wasm_bincodes }
  342. }
  343. }
  344. #[derive(Debug)]
  345. struct BlockchainInfo {
  346. _headers: HeaderStoreInfo,
  347. _blocks: BlockInfoChain,
  348. _order: BlockOrderStoreInfo,
  349. _difficulties: BlockDifficultyStoreInfo,
  350. _transactions: TxStoreInfo,
  351. _pending_txs: PendingTxStoreInfo,
  352. _pending_txs_order: PendingTxOrderStoreInfo,
  353. _contracts: ContractStateStoreInfo,
  354. _wasm_bincode: WasmStoreInfo,
  355. }
  356. impl BlockchainInfo {
  357. pub fn new(blockchain: &Blockchain) -> BlockchainInfo {
  358. BlockchainInfo {
  359. _headers: HeaderStoreInfo::new(&blockchain.headers),
  360. _blocks: BlockInfoChain::new(&blockchain.blocks),
  361. _order: BlockOrderStoreInfo::new(&blockchain.order),
  362. _difficulties: BlockDifficultyStoreInfo::new(&blockchain.difficulties),
  363. _transactions: TxStoreInfo::new(&blockchain.transactions),
  364. _pending_txs: PendingTxStoreInfo::new(&blockchain.pending_txs),
  365. _pending_txs_order: PendingTxOrderStoreInfo::new(&blockchain.pending_txs_order),
  366. _contracts: ContractStateStoreInfo::new(&blockchain.contracts),
  367. _wasm_bincode: WasmStoreInfo::new(&blockchain.wasm_bincode),
  368. }
  369. }
  370. }
  371. fn statistics(folder: &str, node: &str, blockchain: &str) -> Result<()> {
  372. println!("Retrieving blockchain statistics for {node}...");
  373. // Node folder
  374. let folder = folder.to_owned() + node;
  375. // Initialize or load sled database
  376. let path = folder.to_owned() + blockchain;
  377. let db_path = expand_path(&path).unwrap();
  378. let sled_db = sled::open(db_path)?;
  379. // Retrieve statistics
  380. let blockchain = Blockchain::new(&sled_db)?;
  381. let (height, block) = blockchain.last()?;
  382. let epoch = block_epoch(height);
  383. let blocks = blockchain.len();
  384. let txs = blockchain.txs_len();
  385. drop(sled_db);
  386. // Print statistics
  387. println!("Latest height: {height}");
  388. println!("Epoch: {epoch}");
  389. println!("Latest block: {block}");
  390. println!("Total blocks: {blocks}");
  391. println!("Total transactions: {txs}");
  392. Ok(())
  393. }
  394. fn export(folder: &str, node: &str, blockchain: &str) -> Result<()> {
  395. println!("Exporting data for {node}...");
  396. // Node folder
  397. let folder = folder.to_owned() + node;
  398. // Initialize or load sled database
  399. let path = folder.to_owned() + blockchain;
  400. let db_path = expand_path(&path).unwrap();
  401. let sled_db = sled::open(db_path)?;
  402. // Data export
  403. let blockchain = Blockchain::new(&sled_db)?;
  404. let info = BlockchainInfo::new(&blockchain);
  405. let info_string = format!("{:#?}", info);
  406. let file_name = node.to_owned() + "_db";
  407. let mut file = File::create(file_name.clone())?;
  408. file.write_all(info_string.as_bytes())?;
  409. drop(sled_db);
  410. println!("Data exported to file: {file_name}");
  411. Ok(())
  412. }
  413. fn main() -> Result<()> {
  414. // Parse arguments
  415. let args = Args::parse();
  416. println!("Node folder path: {}", args.path);
  417. // Export data for each node
  418. for node in args.node {
  419. if args.export {
  420. export(&args.path, &node, &args.blockchain)?;
  421. continue
  422. }
  423. statistics(&args.path, &node, &args.blockchain)?;
  424. }
  425. Ok(())
  426. }