1use bc_db::mongo_utils;
8use bc_utils::utils;
9use block_chain::wallet::Wallet;
10use bson::Document;
11use mongodb::{Client, Collection};
12use std::collections::HashMap;
13use std::error::Error;
14use std::io::{self, Write};
15use tokio;
16
17#[tokio::main]
21async fn main() -> Result<(), Box<dyn Error>> {
22 let client = Client::with_uri_str("mongodb://localhost:27017").await?;
24 let db = client.database("blockchain_db");
25
26 let blocks_collection = db.collection("blocks");
28 let wallets_collection = db.collection("wallets");
29 let blockchain_collection = db.collection("blockchain");
30
31 let mut blockchain =
33 mongo_utils::load_blockchain(blocks_collection.clone(), blockchain_collection.clone())
34 .await?;
35 let output = utils::list_blockchain(&blockchain);
37 println!("{}", output);
38
39 loop {
40 print!("\n\n");
42 println!("*************** ITEMS ***************");
43 println!("* 1. List Blockchain *");
44 println!("* 2. View Wallet Details *");
45 println!("* 3. Send Crypto Currency *");
46 println!("* 4. Mine Transactions *");
47 println!("* 5. Reset Sample Data *");
48 println!("* 6. Exit *");
49 println!("*************************************\n");
50 print!("Input Choice: ");
51
52 io::stdout().flush().unwrap();
54
55 let mut input = String::new();
57 io::stdin()
58 .read_line(&mut input)
59 .expect("Failed to read line");
60
61 let input = input.trim();
63 match input.parse::<u32>() {
64 Ok(choice) => match choice {
65 1 => {
66 let blockchain = mongo_utils::load_blockchain(
67 blocks_collection.clone(),
68 blockchain_collection.clone(),
69 )
70 .await?;
71 let output = utils::list_blockchain(&blockchain);
72 println!("{}", output);
73 }
74 2 => {
75 let wallet_map: HashMap<String, Wallet> =
77 mongo_utils::load_wallets(wallets_collection.clone()).await?;
78 list_wallets(&wallet_map);
79 list_wallet(&wallet_map);
80 }
81 3 => {
82 send_cc(
87 blocks_collection.clone(),
90 wallets_collection.clone(),
91 blockchain_collection.clone(),
92 )
93 .await;
94 }
95 4 => {
96 mine_transactions(
97 blocks_collection.clone(),
98 blockchain_collection.clone(),
99 wallets_collection.clone(),
100 )
101 .await;
102 }
103 5 => {
104 let result = utils::reset_sample_data(
105 &blocks_collection,
106 &wallets_collection,
107 &blockchain_collection,
108 )
109 .await;
110
111 let new_blockchain = mongo_utils::load_blockchain(
113 blocks_collection.clone(),
114 blockchain_collection.clone(),
115 )
116 .await?;
117 blockchain = new_blockchain;
118
119 print!("{:?}", result);
121 let output = utils::list_blockchain(&blockchain);
122 println!("{}", output);
123 }
124 6 => {
125 println!("Exiting...");
126 break;
127 }
128 _ => println!("Invalid choice. Please enter a number between 1 and 7."),
129 },
130 Err(_) => println!("Invalid input. Please enter a number."),
131 }
132 }
133
134 Ok(())
135}
136
137fn list_wallets(wallet_map: &HashMap<String, Wallet>) {
138 println!("\nAvaiable Wallets:\n");
139 for (address, wallet) in wallet_map {
140 println!("Wallet address: {} and PK: {}", address, wallet.public_key);
141 }
142}
143
144fn list_wallet(wallet_map: &HashMap<String, Wallet>) {
145 print!("\nInput Address of Wallet to display: ");
146 io::stdout().flush().unwrap(); let mut selected_address = String::new();
148 io::stdin()
149 .read_line(&mut selected_address)
150 .expect("Failed to read line");
151 println!("\nWallet selected {}", selected_address);
152 let selected_address = selected_address.trim();
153 if let Some(wallet) = wallet_map.get(selected_address) {
154 let output = utils::view_wallet(&wallet, &wallet.address);
155 println!("{}", output);
156 } else {
157 println!("Address Not Found!")
158 }
159}
160
161async fn send_cc(
162 blocks_collection: Collection<Document>,
165 wallets_collection: Collection<Document>,
166 blockchain_collection: Collection<Document>,
167) {
168 let mut blockchain =
170 mongo_utils::load_blockchain(blocks_collection.clone(), blockchain_collection.clone())
171 .await
172 .unwrap();
173
174 let mut wallet_map: HashMap<String, Wallet> =
176 mongo_utils::load_wallets(wallets_collection.clone())
177 .await
178 .unwrap()
179 .clone();
180 list_wallets(&wallet_map);
181
182 print!("\nInput Sender Wallet Address: ");
183 io::stdout().flush().unwrap(); let mut sender_address = String::new();
185 io::stdin()
186 .read_line(&mut sender_address)
187 .expect("Failed to read line");
188 println!("\nWallet selected: {}", sender_address);
189 let sender_address = sender_address.trim();
190
191 print!("Input Receiver Wallet Address: ");
192 io::stdout().flush().unwrap(); let mut receiver_address = String::new();
194 io::stdin()
195 .read_line(&mut receiver_address)
196 .expect("Failed to read line");
197 println!("\nWallet selected: {}", receiver_address);
198 let receiver_address = receiver_address.trim();
199
200 let mut sender_wallet = wallet_map
201 .remove(sender_address)
202 .expect("Sender wallet not found");
203 let mut receiver_wallet = wallet_map
204 .remove(receiver_address)
205 .expect("Receiver wallet not found");
206
207 let (amount, fee) = get_amount_fees();
208 let msg: String = Result::expect(
209 utils::send_crypto(
210 amount,
211 fee,
212 &mut blockchain,
213 &mut sender_wallet,
214 &mut receiver_wallet,
215 blocks_collection.clone(),
216 wallets_collection.clone(),
217 blockchain_collection.clone(),
218 )
219 .await,
220 "Could not complete Transaction!",
221 );
222 print!("{msg}");
223}
224
225fn get_amount_fees() -> (f64, f64) {
226 let amount = get_input("Please enter the amount to send: ");
227 let fee = get_input("Please enter the fee for mining: ");
228
229 (amount, fee)
230}
231
232fn get_input(msg: &str) -> f64 {
233 loop {
234 print!("{msg}");
236 io::stdout().flush().unwrap(); let mut input = String::new();
239 io::stdin()
240 .read_line(&mut input)
241 .expect("Failed to read line");
242
243 match input.trim().parse::<f64>() {
245 Ok(amt_value) => return amt_value, Err(_) => println!("Invalid input, please enter a valid number"), }
248 }
249}
250
251async fn mine_transactions(
252 blocks_collection: Collection<Document>,
253 blockchain_collection: Collection<Document>,
254 wallets_collection: Collection<Document>,
255) {
256 println!("\nList of Pending Transactions from Mempool\n");
257 let result = utils::get_pending_txrn(&wallets_collection.clone()).await;
258
259 let mut gbl_index = 0;
260 for (_address, transactions) in &result {
261 for txn in transactions.iter() {
262 println!(
263 "No#:-{} tx_id: {:?} timestamp: {} sender: {} receiver: {} amount: {} fee: {}",
264 gbl_index, txn.tx_id, txn.timestamp, txn.sender, txn.receiver, txn.amount, txn.fee
265 );
266 gbl_index += 1;
267 }
268 }
269
270 if gbl_index == 0 {
271 println!("\nNo Pending transactions to mine!\n");
272 return ();
273 }
274
275 println!("Select No# to mine: ");
276 io::stdout().flush().unwrap(); let mut selected_number = String::new();
278 io::stdin()
279 .read_line(&mut selected_number)
280 .expect("Failed to read line");
281
282 let selected_index: usize = selected_number
283 .trim()
284 .parse()
285 .expect("Please enter a valid number");
286
287 gbl_index = 0;
289 let mut selected_tx_id = None;
290 for (_address, transactions) in &result {
291 for txn in transactions.iter() {
292 if gbl_index == selected_index {
293 selected_tx_id = Some(txn.tx_id.clone());
294 break;
295 }
296 gbl_index += 1;
297 }
298 if selected_tx_id.is_some() {
299 break;
300 }
301 }
302
303 let tx_id = selected_tx_id.unwrap();
304
305 utils::mine_crypto(blocks_collection.clone(), blockchain_collection.clone()).await;
306 let response = utils::commit_mine_crypto(
307 tx_id,
308 blocks_collection,
309 blockchain_collection,
310 wallets_collection,
311 )
312 .await;
313 println!("{response}");
314}