From 2ff6caf3fe9a0cc23b4c5648604a89eec91b618f Mon Sep 17 00:00:00 2001 From: Xoulomon <75281652+Xoulomon@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:23:43 +0000 Subject: [PATCH 1/7] chore: create mini_btc crate --- assessment/Cargo.lock | 16 ++++++++++++++++ .../mini_blockchain_clone/Cargo.toml | 12 ++++++++++++ .../mini_blockchain_clone/src/main.rs | 3 +++ 3 files changed, 31 insertions(+) create mode 100644 assessment/Cargo.lock create mode 100644 capstone_projects/mini_blockchain_clone/Cargo.toml create mode 100644 capstone_projects/mini_blockchain_clone/src/main.rs diff --git a/assessment/Cargo.lock b/assessment/Cargo.lock new file mode 100644 index 0000000..afadbb7 --- /dev/null +++ b/assessment/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "rust-week-2-exercises" +version = "0.1.0" +dependencies = [ + "hex", +] diff --git a/capstone_projects/mini_blockchain_clone/Cargo.toml b/capstone_projects/mini_blockchain_clone/Cargo.toml new file mode 100644 index 0000000..6839b24 --- /dev/null +++ b/capstone_projects/mini_blockchain_clone/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mini_blockchain_clone" +version = "0.1.0" +edition = "2024" + +[dependencies] +[dependencies] +sha2 = "0.10" +hex = "0.4" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +rand = "0.9.2" diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 7659bccd2e4ed579d4df95cee596906e7bde8e5b Mon Sep 17 00:00:00 2001 From: Mystery Date: Mon, 8 Dec 2025 09:52:17 +0000 Subject: [PATCH 2/7] feat:add block and blockchain struct , impl and utility function --- .../mini_blockchain_clone/Cargo.lock | 290 ++++++++++++++++++ .../mini_blockchain_clone/Cargo.toml | 1 - .../mini_blockchain_clone/src/main.rs | 182 ++++++++++- 3 files changed, 470 insertions(+), 3 deletions(-) create mode 100644 capstone_projects/mini_blockchain_clone/Cargo.lock diff --git a/capstone_projects/mini_blockchain_clone/Cargo.lock b/capstone_projects/mini_blockchain_clone/Cargo.lock new file mode 100644 index 0000000..054e3e7 --- /dev/null +++ b/capstone_projects/mini_blockchain_clone/Cargo.lock @@ -0,0 +1,290 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mini_blockchain_clone" +version = "0.1.0" +dependencies = [ + "hex", + "rand", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/capstone_projects/mini_blockchain_clone/Cargo.toml b/capstone_projects/mini_blockchain_clone/Cargo.toml index 6839b24..206559e 100644 --- a/capstone_projects/mini_blockchain_clone/Cargo.toml +++ b/capstone_projects/mini_blockchain_clone/Cargo.toml @@ -3,7 +3,6 @@ name = "mini_blockchain_clone" version = "0.1.0" edition = "2024" -[dependencies] [dependencies] sha2 = "0.10" hex = "0.4" diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs index e7a11a9..124fa20 100644 --- a/capstone_projects/mini_blockchain_clone/src/main.rs +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -1,3 +1,181 @@ -fn main() { - println!("Hello, world!"); +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::{self, Write, BufReader}; +use std::time::{SystemTime, UNIX_EPOCH}; +use serde::{Serialize, Deserialize}; + +// Block structure +#[derive(Debug, Clone, Serialize, Deserialize)] +struct Block { + version: u32, + prev_block: String, + merkle_root: String, + timestamp: u32, + bits: String, + nonce: u32, + hash: String, } + +impl Block { + fn new(version: u32, prev_block: String, merkle_root: String, timestamp: u32, bits: String) -> Self { + Block { + version, + prev_block, + merkle_root, + timestamp, + bits, + nonce: 0, + hash: String::new(), + } + } + + fn header(&self) -> String { + format!( + "{}{}{}{}{}{}", + to_little_endian(&format!("{:08x}", self.version)), + reverse_bytes(&self.prev_block), + reverse_bytes(&self.merkle_root), + to_little_endian(&format!("{:08x}", self.timestamp)), + reverse_bytes(&self.bits), + to_little_endian(&format!("{:08x}", self.nonce)) + ) + } + + fn calculate_hash(&mut self) -> String { + let header = self.header(); + let hash = double_sha256(&header); + self.hash = reverse_bytes(&hash); + self.hash.clone() + } +} + +// Blockchain structure +struct Blockchain { + blocks: Vec, + difficulty_target: String, +} + +impl Blockchain { + fn new(difficulty_target: String) -> Self { + Blockchain { + blocks: Vec::new(), + difficulty_target, + } + } + + fn add_block(&mut self, block: Block) { + self.blocks.push(block); + } + + fn get_latest_block(&self) -> Option<&Block> { + self.blocks.last() + } + + fn mine_block(&mut self, mut block: Block) -> Block { + println!("\nšŸ”Ø Mining block..."); + println!("Target: {}", self.difficulty_target); + println!(); + + let required_zeros = 2; + + let target_prefix = "0".repeat(required_zeros * 2); // e.g., "00000000" for 4 hex zeros (2 bytes). + + let mut nonce = 0u32; + loop { + block.nonce = nonce; + let hash = block.calculate_hash(); + + // CHANGE: Simple leading zeros check for easy, accurate PoW validation. + if hash.starts_with(&target_prefix) { + println!("\nāœ… Block mined successfully!"); + println!("Nonce: {}", nonce); + println!("Hash: {}", hash); + break; + } + + if nonce % 10000 == 0 { + println!("Nonce: {} | Hash: {}", nonce, &hash[..16]); // Truncate for output. + } + + nonce += 1; + + // Safety: Prevent infinite loop if something's wrong. + if nonce > 1_000_000 { + println!("āš ļø Mining timeout - difficulty too high?"); + break; + } + } + block + } + + fn is_valid(&self) -> bool { + for i in 1..self.blocks.len() { + let current = &self.blocks[i]; + let previous = &self.blocks[i - 1]; + + // Verify hash + let mut temp_block = current.clone(); + temp_block.calculate_hash(); + if temp_block.hash != current.hash { + println!("āŒ Invalid hash at block {}", i); + return false; + } + + // Verify chain linkage + if current.prev_block != previous.hash { + println!("āŒ Invalid previous block reference at block {}", i); + return false; + } + + // CHANGE: Use same leading zeros check for validation. + let required_zeros = 2; + let target_prefix = "0".repeat(required_zeros * 2); + if !current.hash.starts_with(&target_prefix) { + println!("āŒ Block {} doesn't meet difficulty target", i); + return false; + } + } + true + } + + fn save_to_disk(&self, filename: &str) -> io::Result<()> { + let json = serde_json::to_string_pretty(&self.blocks)?; + let mut file = File::create(filename)?; + file.write_all(json.as_bytes())?; + println!("šŸ’¾ Blockchain saved to {}", filename); + Ok(()) + } + + fn load_from_disk(&mut self, filename: &str) -> io::Result<()> { + let file = File::open(filename)?; + let reader = BufReader::new(file); + self.blocks = serde_json::from_reader(reader)?; + println!("šŸ“‚ Blockchain loaded from {}", filename); + Ok(()) + } +} + +// Utility functions +fn double_sha256(hex_string: &str) -> String { + let bytes = hex::decode(hex_string).expect("Invalid hex string"); + let hash1 = Sha256::digest(&bytes); + let hash2 = Sha256::digest(&hash1); + hex::encode(hash2) +} + +fn reverse_bytes(hex_string: &str) -> String { + let mut chars: Vec = hex_string.chars().collect(); + chars.chunks_exact_mut(2).rev().for_each(|chunk| { + chunk.swap(0, 1); + }); + chars.into_iter().collect() +} + +fn to_little_endian(hex_string: &str) -> String { + let padded = format!("{:0>8}", hex_string); // Pad to 8 hex chars (4 bytes). + reverse_bytes(&padded) +} + +fn main( ) { + +} \ No newline at end of file From b12766a56df5f8f7e799ccbef86dfc808353a8a3 Mon Sep 17 00:00:00 2001 From: Xoulomon <75281652+Xoulomon@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:30:50 +0000 Subject: [PATCH 3/7] feat: add functionality to mine block , save and load blockchain --- .../mini_blockchain_clone/src/main.rs | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs index 124fa20..5dff25b 100644 --- a/capstone_projects/mini_blockchain_clone/src/main.rs +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -176,6 +176,167 @@ fn to_little_endian(hex_string: &str) -> String { reverse_bytes(&padded) } +fn pause() { + println!("\nPress Enter to continue..."); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); +} + +fn clear_screen() { + print!("\x1B[2J\x1B[1;1H"); + io::stdout().flush().unwrap(); +} + +fn mine_new_block(blockchain: &mut Blockchain) { + let prev_block = if let Some(last) = blockchain.get_latest_block() { + last.hash.clone() + } else { + "0000000000000000000000000000000000000000000000000000000000000000".to_string() + }; + + println!("\nšŸ“ Enter block details:"); + println!("Merkle root (or press Enter for default): "); + let mut merkle_root = String::new(); + io::stdin().read_line(&mut merkle_root).unwrap(); + let merkle_root = if merkle_root.trim().is_empty() { + // Generate a simple random-like merkle root from timestamp + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + format!("{:064x}", now) + } else { + merkle_root.trim().to_string() + }; + + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as u32; + + let block = Block::new( + 1, + prev_block, + merkle_root, + timestamp, + "1a6a93b3".to_string(), + ); + + let mined_block = blockchain.mine_block(block); + blockchain.add_block(mined_block); + + println!("\n✨ Block added to blockchain!"); + + // CHANGE: Automatically save to JSON after mining. + if let Err(e) = blockchain.save_to_disk("blockchain.json") { + println!("āš ļø Warning: Could not auto-save blockchain: {}", e); + } else { + println!("šŸ’¾ Auto-saved to blockchain.json"); + } +} + +fn view_blockchain(blockchain: &Blockchain) { + if blockchain.blocks.is_empty() { + println!("\nšŸ“­ Blockchain is empty!"); + return; + } + + println!("\nšŸ“š Blockchain ({} blocks):", blockchain.blocks.len()); + println!("════════════════════════════════════════"); + + for (i, block) in blockchain.blocks.iter().enumerate() { + println!("\nšŸ”— Block {}", i); + println!(" Version: {}", block.version); + println!(" Prev Block: {}", block.prev_block); + println!(" Merkle Root: {}", block.merkle_root); + println!(" Timestamp: {}", block.timestamp); + println!(" Bits: {}", block.bits); + println!(" Nonce: {}", block.nonce); + println!(" Hash: {}", block.hash); + } +} + +fn validate_blockchain(blockchain: &Blockchain) { + println!("\nšŸ” Validating blockchain..."); + + if blockchain.is_valid() { + println!("āœ… Blockchain is valid!"); + } else { + println!("āŒ Blockchain is invalid!"); + } +} + +fn run_simulation() { + clear_screen(); + println!("Mining Simulator"); + pause(); + + println!("\n1. Get Transactions"); + println!("-------------------"); + println!("transactions: 13(including coinbase)"); + pause(); + + let version = "1"; + let prevblock = "0000000000000b60bc96a44724fd72daf9b92cf8ad00510b5224c6253ac40095"; + let merkleroot = "0e60651a9934e8f0decd1c5fde39309e48fca0cd1c84a21ddfde95033762d86c"; + let time = 1305200806u32; + let bits = "1affffff"; + + println!("\n2. Block"); + println!("--------"); + println!("version: {}", version); + println!("prevblock: {}", prevblock); + println!("merkleroot: {}", merkleroot); + println!("time: {} (timestamp)", time); + println!("bits: {}", bits); + println!("nonce: ________"); + pause(); + + let header = format!( + "{}{}{}{}{}", + to_little_endian(&format!("{:08x}", 1)), + reverse_bytes(prevblock), + reverse_bytes(merkleroot), + to_little_endian(&format!("{:08x}", time)), + reverse_bytes(bits) + ); + + println!("\nHeader: {}________", header); + pause(); + + // CHANGE: Easy target for simulation - requires only 2 leading zero bytes (very fast mining). + let target = "000000000000ffffff0000000000000000000000000000000000000000000000"; + println!("\n3. Target"); + println!("---------"); + println!("{}", target); + pause(); + + let block = Block::new(1, prevblock.to_string(), merkleroot.to_string(), time, bits.to_string()); + let mut blockchain = Blockchain::new(target.to_string()); + blockchain.mine_block(block); +} + +// For ANSI orange (no deps): Define constants for orange (256-color code 208). +const ORANGE: &str = "\x1b[38;5;208m"; +const RESET: &str = "\x1b[0m"; + +fn print_bitcoin_logo() { + let logo_lines = vec![ + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–„ā–„ā–ˆā–€ā–€ā–€ā–€ā–€ā–ˆā–„ā–„ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–„ā–ˆā–€ā–‘ā–‘ā–„ā–‘ā–„ā–‘ā–‘ā–‘ā–‘ā–€ā–ˆā–„ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–€ā–ˆā–€ā–€ā–€ā–€ā–„ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–ˆā–„ā–„ā–„ā–„ā–€ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–€ā–ˆā–„ā–‘ā–€ā–€ā–ˆā–€ā–ˆā–€ā–‘ā–‘ā–„ā–ˆā–€ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + "ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–€ā–€ā–ˆā–„ā–„ā–„ā–„ā–„ā–ˆā–€ā–€ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘", + ]; + + for line in logo_lines { + println!("{ORANGE}{line}{RESET}"); + } + println!(); // Extra space after logo. +} + fn main( ) { } \ No newline at end of file From ce7d369bc5202dd011acd9d3ec26d34704dcd9ff Mon Sep 17 00:00:00 2001 From: Mystery Date: Tue, 9 Dec 2025 10:37:51 +0000 Subject: [PATCH 4/7] feat: add main implementaion --- .../mini_blockchain_clone/blockchain.json | 11 ++++ .../mini_blockchain_clone/src/main.rs | 55 ++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 capstone_projects/mini_blockchain_clone/blockchain.json diff --git a/capstone_projects/mini_blockchain_clone/blockchain.json b/capstone_projects/mini_blockchain_clone/blockchain.json new file mode 100644 index 0000000..b909ab9 --- /dev/null +++ b/capstone_projects/mini_blockchain_clone/blockchain.json @@ -0,0 +1,11 @@ +[ + { + "version": 1, + "prev_block": "0000000000000000000000000000000000000000000000000000000000000000", + "merkle_root": "000000000000000000000000000000000000000000000000187f85b643c2daee", + "timestamp": 1765276596, + "bits": "1a6a93b3", + "nonce": 31690, + "hash": "00004c3cd4150b59050f1df062039dc058812e660cbe5488b9709218e8ffa0fb" + } +] \ No newline at end of file diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs index 5dff25b..0b1dd7c 100644 --- a/capstone_projects/mini_blockchain_clone/src/main.rs +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -338,5 +338,58 @@ fn print_bitcoin_logo() { } fn main( ) { - + clear_screen(); + + let mut blockchain = Blockchain::new( + "000000000000ffffff0000000000000000000000000000000000000000000000".to_string() + ); + + // target = '0000000000006a93b30000000000000000000000000000000000000000000000' //harder target + + // Try to load existing blockchain + let _ = blockchain.load_from_disk("blockchain.json"); + + loop { + println!("\n{ORANGE}╔═══════════════════════════════════════╗{RESET}"); + println!("{ORANGE}ā•‘ Mini Bitcoin Blockchain CLI ā•‘{RESET}"); + println!("{ORANGE}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•{RESET}"); + + print_bitcoin_logo(); + + println!("\n{ORANGE}1. Run mining simulation {RESET}"); + println!("{ORANGE}2. View blockchain{RESET}"); + println!("{ORANGE}3. Validate blockchain{RESET}"); + println!("{ORANGE}4. Save blockchain to disk{RESET}"); + println!("{ORANGE}5. Load blockchain from disk{RESET}"); + println!("{ORANGE}6. Mine new block (interactive){RESET}"); + println!("{ORANGE}7. Exit{RESET}"); + println!("\nSelect an option: "); + + let mut choice = String::new(); + io::stdin().read_line(&mut choice).unwrap(); + + match choice.trim() { + "1" => run_simulation(), + "2" => view_blockchain(&blockchain), + "3" => validate_blockchain(&blockchain), + "4" => { + if let Err(e) = blockchain.save_to_disk("blockchain.json") { + println!("Error saving: {}", e); + } + } + "5" => { + if let Err(e) = blockchain.load_from_disk("blockchain.json") { + println!("Error loading: {}", e); + } + } + "6" => mine_new_block(&mut blockchain), // CHANGE: Now accessible via menu. + "7" => { + println!("Goodbye! šŸ‘‹"); + break; + } + _ => println!("Invalid option!"), + } + + pause(); // CHANGE: Add pause after each action for better UX. + } } \ No newline at end of file From e5f647600c9705ec7f0b274ac858b89b38012929 Mon Sep 17 00:00:00 2001 From: Xoulomon <75281652+Xoulomon@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:45:42 +0000 Subject: [PATCH 5/7] fix: remove save blockchain from main.rs --- .../mini_blockchain_clone/blockchain.json | 18 ++++++++++++++++++ .../mini_blockchain_clone/src/main.rs | 16 +++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/capstone_projects/mini_blockchain_clone/blockchain.json b/capstone_projects/mini_blockchain_clone/blockchain.json index b909ab9..025f58a 100644 --- a/capstone_projects/mini_blockchain_clone/blockchain.json +++ b/capstone_projects/mini_blockchain_clone/blockchain.json @@ -7,5 +7,23 @@ "bits": "1a6a93b3", "nonce": 31690, "hash": "00004c3cd4150b59050f1df062039dc058812e660cbe5488b9709218e8ffa0fb" + }, + { + "version": 1, + "prev_block": "00004c3cd4150b59050f1df062039dc058812e660cbe5488b9709218e8ffa0fb", + "merkle_root": "000000000000000000000000000000000000000000000000187f861e8d56eff9", + "timestamp": 1765277044, + "bits": "1a6a93b3", + "nonce": 21264, + "hash": "0000db7643369429f7db588b4b01bc9eea7fdf742230aec41ff524b8cd579c4a" + }, + { + "version": 1, + "prev_block": "0000db7643369429f7db588b4b01bc9eea7fdf742230aec41ff524b8cd579c4a", + "merkle_root": "000000000000000000000000000000000000000000000000187f8622d63c78a8", + "timestamp": 1765277063, + "bits": "1a6a93b3", + "nonce": 130100, + "hash": "000022ae88b4fe3c5501d8d64b22609c2a749d02091a1418ddc8dbccbcbf6254" } ] \ No newline at end of file diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs index 0b1dd7c..db5dd3b 100644 --- a/capstone_projects/mini_blockchain_clone/src/main.rs +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -359,10 +359,9 @@ fn main( ) { println!("\n{ORANGE}1. Run mining simulation {RESET}"); println!("{ORANGE}2. View blockchain{RESET}"); println!("{ORANGE}3. Validate blockchain{RESET}"); - println!("{ORANGE}4. Save blockchain to disk{RESET}"); - println!("{ORANGE}5. Load blockchain from disk{RESET}"); - println!("{ORANGE}6. Mine new block (interactive){RESET}"); - println!("{ORANGE}7. Exit{RESET}"); + println!("{ORANGE}4. Load blockchain from disk{RESET}"); + println!("{ORANGE}5. Mine new block (interactive){RESET}"); + println!("{ORANGE}6. Exit{RESET}"); println!("\nSelect an option: "); let mut choice = String::new(); @@ -373,17 +372,12 @@ fn main( ) { "2" => view_blockchain(&blockchain), "3" => validate_blockchain(&blockchain), "4" => { - if let Err(e) = blockchain.save_to_disk("blockchain.json") { - println!("Error saving: {}", e); - } - } - "5" => { if let Err(e) = blockchain.load_from_disk("blockchain.json") { println!("Error loading: {}", e); } } - "6" => mine_new_block(&mut blockchain), // CHANGE: Now accessible via menu. - "7" => { + "5" => mine_new_block(&mut blockchain), // CHANGE: Now accessible via menu. + "6" => { println!("Goodbye! šŸ‘‹"); break; } From dd4b9955ce42955d4be356d081c12226c9197e9b Mon Sep 17 00:00:00 2001 From: Xoulomon <75281652+Xoulomon@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:52:37 +0000 Subject: [PATCH 6/7] chore: add documentation --- .../mini_blockchain_clone/README.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 capstone_projects/mini_blockchain_clone/README.md diff --git a/capstone_projects/mini_blockchain_clone/README.md b/capstone_projects/mini_blockchain_clone/README.md new file mode 100644 index 0000000..71157b0 --- /dev/null +++ b/capstone_projects/mini_blockchain_clone/README.md @@ -0,0 +1,53 @@ +# Mini Bitcoin Blockchain CLI Simulator + +## Overview + +Rust CLI simulator for Bitcoin-like blockchain basics: block creation, PoW mining (simplified: 2 leading zero bytes), validation, JSON persistence, and interactive mining. Educational tool for blockchain concepts. + +**Features**: +- Interactive mining with custom Merkle roots. +- Step-by-step simulation. +- Auto-save/load from `blockchain.json`. +- Chain validation (hashes, links, PoW). + +**Limitations**: +- Fixed low difficulty; no real txns/network. +- Mining timeout: 1M nonces. + +## Prerequisites & Dependencies + +- Rust 1.70+. +- `Cargo.toml`: + ```toml + [dependencies] + sha2 = "0.10" + serde = { version = "1.0", features = ["derive"] } + serde_json = "1.0" + hex = "0.4" + ``` + +## CLI Functions + +- `mine_new_block(&mut bc)`: Prompt Merkle; mine/add/save. +- `view_blockchain(&bc)`: Print chain details. +- `validate_blockchain(&bc)`: Run `is_valid`. +- `run_simulation()`: Tutorial with fixed params; demo mine. + +## Main Loop + +- Init `Blockchain` (easy target); load JSON. +- Menu: 1=Sim, 2=View, 3=Validate, 4=Load, 5=Mine, 6=Exit. +- Pauses post-action; orange styling. + +## Build/Run + +`cargo build && cargo run` + +**Example Mining Output**: +``` +šŸ”Ø Mining block... +Target: 000000000000ffffff... +Nonce: 12345 | Hash: 0000abcd... +āœ… Block mined! Nonce: 12345 +✨ Added; šŸ’¾ Saved. +``` From 869abfd763289c3efcff2f564098ffb908be19f4 Mon Sep 17 00:00:00 2001 From: Xoulomon <75281652+Xoulomon@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:54:41 +0000 Subject: [PATCH 7/7] fix: adjust banner --- capstone_projects/mini_blockchain_clone/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capstone_projects/mini_blockchain_clone/src/main.rs b/capstone_projects/mini_blockchain_clone/src/main.rs index db5dd3b..c6b8cc3 100644 --- a/capstone_projects/mini_blockchain_clone/src/main.rs +++ b/capstone_projects/mini_blockchain_clone/src/main.rs @@ -351,7 +351,7 @@ fn main( ) { loop { println!("\n{ORANGE}╔═══════════════════════════════════════╗{RESET}"); - println!("{ORANGE}ā•‘ Mini Bitcoin Blockchain CLI ā•‘{RESET}"); + println!("{ORANGE}ā•‘ Mini Bitcoin Blockchain CLI ā•‘{RESET}"); println!("{ORANGE}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•{RESET}"); print_bitcoin_logo();