main.rs 13 KB

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