main.rs 11 KB

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