bc_db/
mongo_utils.rs

1//!
2//! This is the MongoDB_Utils module.<br>
3//! To do CRUD operations for the blockcahin.
4//!
5
6use block_chain::block::Block;
7use block_chain::blockchain::Blockchain;
8use block_chain::wallet::{Transaction, Wallet};
9use futures::stream::TryStreamExt;
10use futures::StreamExt;
11use mongodb::{
12    bson::{self, doc, Document},
13    Collection,
14};
15use std::collections::HashMap;
16use std::error::Error;
17
18///
19/// Functions Reset Sample Data.
20///
21pub async fn reset_sample_data(
22    blockchain_collection: Collection<Document>,
23    blocks_collection: Collection<Document>,
24    wallets_collection: Collection<Document>,
25) -> Result<(), Box<dyn Error>> {
26    println!("Resetting Sample Data...");
27
28    // Clear existing blockchain
29    blockchain_collection.delete_many(doc! {}).await?;
30
31    // Clear existing blocks
32    blocks_collection.delete_many(doc! {}).await?;
33
34    // Clear existing wallets
35    wallets_collection.delete_many(doc! {}).await?;
36
37    // Sample data for blockchain and wallets
38    let genesis_blockchain = doc! {
39        "id": 1,
40        "chain": [
41            {
42                "block_index": 0,
43                "timestamp": 0,
44                "previous_hash": "0",
45                "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
46                "data": "Genesis Block",
47                "miner_address": "genesis_miner_address",
48                "transactions": []
49            }
50        ],
51        "mempool": []
52    };
53
54    let genesis_block = doc! {
55        "block_index": 0,
56        "timestamp": 0,
57        "previous_hash": "0",
58        "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
59        "data": "Genesis Block",
60        "miner_address": "genesis_miner_address",
61        "transactions": []
62    };
63
64    let wallet1_data = doc! {
65        "address": "address1",
66        "private_key": "private_key1",
67        "public_key": "public_key1",
68        "balance": 50.0,
69        "transaction_history": [],
70        "pending_transactions": []
71    };
72
73    let wallet2_data = doc! {
74        "address": "address2",
75        "private_key": "private_key2",
76        "public_key": "public_key2",
77        "balance": 20.0,
78        "transaction_history": [],
79        "pending_transactions": []
80    };
81
82    // Insert genesis blockchain
83    blockchain_collection.insert_one(genesis_blockchain).await?;
84
85    // Insert genesis block
86    blocks_collection.insert_one(genesis_block).await?;
87
88    // Insert new wallets
89    wallets_collection.insert_one(wallet1_data).await?;
90    wallets_collection.insert_one(wallet2_data).await?;
91
92    println!("Sample data has been reset.\n");
93
94    Ok(())
95}
96
97///
98/// Functions to Read the Blockchain.
99///
100pub async fn load_blockchain(
101    blocks_collection: Collection<Document>,
102    blockchain_collection: Collection<Document>,
103) -> Result<Blockchain, Box<dyn Error>> {
104    let mut blockchain = Blockchain::new();
105
106    // Load from `blocks` collection
107    println!("\nLoading blocks from MongoDB:");
108
109    let mut cursor = blocks_collection.find(doc! {}).await?;
110    while let Some(result) = cursor.try_next().await? {
111        let block: Block = bson::from_document(result)?;
112        // let pretty_block =
113        //     serde_json::to_string_pretty(&block).expect("Failed to pretty print block");
114        // println!("{}", pretty_block);
115        blockchain.chain.push(block);
116    }
117
118    // Load from `blockchain` collection
119    let blockchain_doc = blockchain_collection.find_one(doc! { "id": 1 }).await?;
120    if let Some(doc) = blockchain_doc {
121        let chain: Vec<Block> =
122            bson::from_bson(doc.get("chain").unwrap().clone()).unwrap_or_default();
123        for block in chain {
124            if !blockchain.chain.contains(&block) {
125                blockchain.chain.push(block);
126            }
127        }
128
129        // Load the mempool field
130        let mempool: Vec<Transaction> =
131            bson::from_bson(doc.get("mempool").unwrap().clone()).unwrap_or_default();
132        blockchain.mempool = mempool;
133    }
134
135    Ok(blockchain)
136}
137
138///
139/// Functions to Read Wallet.
140///
141pub async fn load_wallet(
142    wallets_collection: Collection<Document>,
143    address: &str,
144) -> Result<Wallet, Box<dyn Error>> {
145    let filter = doc! {"address": address};
146    let result = wallets_collection.find_one(filter).await?;
147
148    if let Some(doc) = result {
149        let wallet: Wallet = bson::from_document(doc)?;
150        Ok(wallet)
151    } else {
152        Err("Wallet not found".into())
153    }
154}
155
156///
157/// Functions to Load all Wallets.
158///
159pub async fn load_wallets(
160    wallets_collection: Collection<Document>,
161) -> Result<HashMap<String, Wallet>, Box<dyn Error>> {
162    // Create a HashMap to store wallets
163    let mut wallet_map: HashMap<String, Wallet> = HashMap::new();
164
165    // Retrieve all documents from the collection
166    let mut cursor = wallets_collection.find(doc! {}).await?;
167
168    // Iterate through the results and insert into the HashMap
169    while let Some(result) = cursor.next().await {
170        if let Ok(doc) = result {
171            let wallet: Wallet = bson::from_document(doc)?;
172            wallet_map.insert(wallet.address.clone(), wallet);
173        }
174    }
175
176    Ok(wallet_map)
177}
178
179///
180/// Functions to Update Blockchain.
181///
182pub async fn save_blockchain(
183    blockchain: &Blockchain,
184    blocks_collection: Collection<Document>,
185    blockchain_collection: Collection<Document>,
186) -> Result<(), Box<dyn Error>> {
187    // Drop and save individual blocks
188    blocks_collection.drop().await?;
189    for block in &blockchain.chain {
190        let doc = bson::to_document(block)?;
191        blocks_collection.insert_one(doc).await?;
192    }
193
194    // Save the entire blockchain
195    let blockchain_doc = doc! {
196        "id": 1,
197        "chain": bson::to_bson(&blockchain.chain)?,
198        "mempool": bson::to_bson(&blockchain.mempool)?
199    };
200    blockchain_collection
201        .update_one(doc! { "id": 1 }, doc! { "$set": blockchain_doc })
202        .await?;
203
204    Ok(())
205}
206
207///
208/// Functions to Update Wallet.
209///
210pub async fn save_wallet(
211    wallet: Wallet,
212    wallets_collection: Collection<Document>,
213) -> Result<(), Box<dyn Error>> {
214    let filter = doc! {"address": wallet.address.clone()};
215    let update = bson::to_document(&wallet)?;
216    wallets_collection.replace_one(filter, update).await?;
217    Ok(())
218}