├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src ├── blockchain.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.0.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 10 | 11 | [[package]] 12 | name = "block-buffer" 13 | version = "0.10.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" 16 | dependencies = [ 17 | "generic-array", 18 | ] 19 | 20 | [[package]] 21 | name = "blockchain" 22 | version = "0.1.0" 23 | dependencies = [ 24 | "chrono", 25 | "serde", 26 | "serde_derive", 27 | "serde_json", 28 | "sha2", 29 | ] 30 | 31 | [[package]] 32 | name = "cfg-if" 33 | version = "1.0.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 36 | 37 | [[package]] 38 | name = "chrono" 39 | version = "0.4.19" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 42 | dependencies = [ 43 | "libc", 44 | "num-integer", 45 | "num-traits", 46 | "time", 47 | "winapi", 48 | ] 49 | 50 | [[package]] 51 | name = "cpufeatures" 52 | version = "0.2.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 55 | dependencies = [ 56 | "libc", 57 | ] 58 | 59 | [[package]] 60 | name = "crypto-common" 61 | version = "0.1.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" 64 | dependencies = [ 65 | "generic-array", 66 | ] 67 | 68 | [[package]] 69 | name = "digest" 70 | version = "0.10.1" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" 73 | dependencies = [ 74 | "block-buffer", 75 | "crypto-common", 76 | "generic-array", 77 | ] 78 | 79 | [[package]] 80 | name = "generic-array" 81 | version = "0.14.5" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 84 | dependencies = [ 85 | "typenum", 86 | "version_check", 87 | ] 88 | 89 | [[package]] 90 | name = "itoa" 91 | version = "1.0.1" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 94 | 95 | [[package]] 96 | name = "libc" 97 | version = "0.2.112" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 100 | 101 | [[package]] 102 | name = "num-integer" 103 | version = "0.1.44" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 106 | dependencies = [ 107 | "autocfg", 108 | "num-traits", 109 | ] 110 | 111 | [[package]] 112 | name = "num-traits" 113 | version = "0.2.14" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 116 | dependencies = [ 117 | "autocfg", 118 | ] 119 | 120 | [[package]] 121 | name = "proc-macro2" 122 | version = "1.0.36" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 125 | dependencies = [ 126 | "unicode-xid", 127 | ] 128 | 129 | [[package]] 130 | name = "quote" 131 | version = "1.0.14" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" 134 | dependencies = [ 135 | "proc-macro2", 136 | ] 137 | 138 | [[package]] 139 | name = "ryu" 140 | version = "1.0.9" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 143 | 144 | [[package]] 145 | name = "serde" 146 | version = "1.0.133" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" 149 | 150 | [[package]] 151 | name = "serde_derive" 152 | version = "1.0.133" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" 155 | dependencies = [ 156 | "proc-macro2", 157 | "quote", 158 | "syn", 159 | ] 160 | 161 | [[package]] 162 | name = "serde_json" 163 | version = "1.0.75" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79" 166 | dependencies = [ 167 | "itoa", 168 | "ryu", 169 | "serde", 170 | ] 171 | 172 | [[package]] 173 | name = "sha2" 174 | version = "0.10.1" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" 177 | dependencies = [ 178 | "cfg-if", 179 | "cpufeatures", 180 | "digest", 181 | ] 182 | 183 | [[package]] 184 | name = "syn" 185 | version = "1.0.85" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" 188 | dependencies = [ 189 | "proc-macro2", 190 | "quote", 191 | "unicode-xid", 192 | ] 193 | 194 | [[package]] 195 | name = "time" 196 | version = "0.1.44" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 199 | dependencies = [ 200 | "libc", 201 | "wasi", 202 | "winapi", 203 | ] 204 | 205 | [[package]] 206 | name = "typenum" 207 | version = "1.15.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 210 | 211 | [[package]] 212 | name = "unicode-xid" 213 | version = "0.2.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 216 | 217 | [[package]] 218 | name = "version_check" 219 | version = "0.9.4" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 222 | 223 | [[package]] 224 | name = "wasi" 225 | version = "0.10.0+wasi-snapshot-preview1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 228 | 229 | [[package]] 230 | name = "winapi" 231 | version = "0.3.9" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 234 | dependencies = [ 235 | "winapi-i686-pc-windows-gnu", 236 | "winapi-x86_64-pc-windows-gnu", 237 | ] 238 | 239 | [[package]] 240 | name = "winapi-i686-pc-windows-gnu" 241 | version = "0.4.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 244 | 245 | [[package]] 246 | name = "winapi-x86_64-pc-windows-gnu" 247 | version = "0.4.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 250 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blockchain" 3 | version = "0.1.0" 4 | authors = ["tensor-programming "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | chrono = "0.4" 9 | serde = "1.0" 10 | serde_derive = "1.0" 11 | serde_json = "1.0" 12 | sha2 = "0.10.1" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust_block_chain 2 | 3 | # A simple rust CLI block chain project 4 | 5 | ## Run `cargo run` to run the app, run `cargo build` to build an executable file. 6 | 7 | ### Check out the Youtube Tutorial for this [Rust Tutorial](https://youtu.be/U8GGZ4TqlQs). Here is our [Youtube Channel](https://www.youtube.com/channel/UCYqCZOwHbnPwyjawKfE21wg) Subscribe for more content. 8 | 9 | ### Check out our blog at [tensor-programming.com](http://tensor-programming.com/). 10 | 11 | ### Our [Twitter](https://twitter.com/TensorProgram), our [facebook](https://www.facebook.com/Tensor-Programming-1197847143611799/) and our [Steemit](https://steemit.com/@tensor). 12 | -------------------------------------------------------------------------------- /src/blockchain.rs: -------------------------------------------------------------------------------- 1 | use serde_derive::{Deserialize, Serialize}; 2 | use sha2::{Digest, Sha256}; 3 | use std::fmt::Write; 4 | 5 | use chrono::prelude::*; 6 | 7 | #[derive(Debug, Clone, Serialize)] 8 | struct Transaction { 9 | sender: String, 10 | receiver: String, 11 | amount: f32, 12 | } 13 | 14 | #[derive(Serialize, Debug)] 15 | pub struct Blockheader { 16 | timestamp: i64, 17 | nonce: u32, 18 | pre_hash: String, 19 | merkle: String, 20 | difficulty: u32, 21 | } 22 | 23 | #[derive(Serialize, Debug)] 24 | pub struct Block { 25 | header: Blockheader, 26 | count: u32, 27 | transactions: Vec, 28 | } 29 | 30 | pub struct Chain { 31 | chain: Vec, 32 | curr_trans: Vec, 33 | difficulty: u32, 34 | miner_addr: String, 35 | reward: f32, 36 | } 37 | 38 | impl Chain { 39 | pub fn new(miner_addr: String, difficulty: u32) -> Chain { 40 | let mut chain = Chain { 41 | chain: Vec::new(), 42 | curr_trans: Vec::new(), 43 | difficulty, 44 | miner_addr, 45 | reward: 100.0, 46 | }; 47 | 48 | chain.generate_new_block(); 49 | chain 50 | } 51 | 52 | pub fn new_transaction(&mut self, sender: String, receiver: String, amount: f32) -> bool { 53 | self.curr_trans.push(Transaction { 54 | sender, 55 | receiver, 56 | amount, 57 | }); 58 | 59 | true 60 | } 61 | 62 | pub fn last_hash(&self) -> String { 63 | let block = match self.chain.last() { 64 | Some(block) => block, 65 | None => return String::from_utf8(vec![48; 64]).unwrap(), 66 | }; 67 | Chain::hash(&block.header) 68 | } 69 | 70 | pub fn update_difficulty(&mut self, difficulty: u32) -> bool { 71 | self.difficulty = difficulty; 72 | true 73 | } 74 | 75 | pub fn update_reward(&mut self, reward: f32) -> bool { 76 | self.reward = reward; 77 | true 78 | } 79 | 80 | pub fn generate_new_block(&mut self) -> bool { 81 | let header = Blockheader { 82 | timestamp: Utc::now().timestamp_millis(), 83 | nonce: 0, 84 | pre_hash: self.last_hash(), 85 | merkle: String::new(), 86 | difficulty: self.difficulty, 87 | }; 88 | 89 | let reward_trans = Transaction { 90 | sender: String::from("Root"), 91 | receiver: self.miner_addr.clone(), 92 | amount: self.reward, 93 | }; 94 | 95 | let mut block = Block { 96 | header, 97 | count: 0, 98 | transactions: vec![], 99 | }; 100 | 101 | block.transactions.push(reward_trans); 102 | block.transactions.append(&mut self.curr_trans); 103 | block.count = block.transactions.len() as u32; 104 | block.header.merkle = Chain::get_merkle(block.transactions.clone()); 105 | Chain::proof_of_work(&mut block.header); 106 | 107 | println!("{:#?}", &block); 108 | self.chain.push(block); 109 | true 110 | } 111 | 112 | fn get_merkle(curr_trans: Vec) -> String { 113 | let mut merkle = Vec::new(); 114 | 115 | for t in &curr_trans { 116 | let hash = Chain::hash(t); 117 | merkle.push(hash); 118 | } 119 | 120 | if merkle.len() % 2 == 1 { 121 | let last = merkle.last().cloned().unwrap(); 122 | merkle.push(last); 123 | } 124 | 125 | while merkle.len() > 1 { 126 | let mut h1 = merkle.remove(0); 127 | let mut h2 = merkle.remove(0); 128 | h1.push_str(&mut h2); 129 | let nh = Chain::hash(&h1); 130 | merkle.push(nh); 131 | } 132 | merkle.pop().unwrap() 133 | } 134 | 135 | pub fn proof_of_work(header: &mut Blockheader) { 136 | loop { 137 | let hash = Chain::hash(header); 138 | let slice = &hash[..header.difficulty as usize]; 139 | match slice.parse::() { 140 | Ok(val) => { 141 | if val != 0 { 142 | header.nonce += 1; 143 | } else { 144 | println!("Block hash: {}", hash); 145 | break; 146 | } 147 | } 148 | Err(_) => { 149 | header.nonce += 1; 150 | continue; 151 | } 152 | }; 153 | } 154 | } 155 | 156 | pub fn hash(item: &T) -> String { 157 | let input = serde_json::to_string(&item).unwrap(); 158 | let mut hasher = Sha256::new(); 159 | hasher.update(input.as_bytes()); 160 | let res = hasher.finalize(); 161 | let vec_res = res.to_vec(); 162 | 163 | Chain::hex_to_string(vec_res.as_slice()) 164 | } 165 | 166 | pub fn hex_to_string(vec_res: &[u8]) -> String { 167 | let mut s = String::new(); 168 | for b in vec_res { 169 | write!(&mut s, "{:x}", b).expect("unable to write"); 170 | } 171 | s 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::Write; 3 | use std::process; 4 | 5 | mod blockchain; 6 | 7 | fn main() { 8 | let mut miner_addr = String::new(); 9 | let mut difficulty = String::new(); 10 | let mut choice = String::new(); 11 | 12 | print!("input a miner address: "); 13 | io::stdout().flush(); 14 | io::stdin().read_line(&mut miner_addr); 15 | print!("Difficulty: "); 16 | io::stdout().flush(); 17 | io::stdin().read_line(&mut difficulty); 18 | let diff = difficulty 19 | .trim() 20 | .parse::() 21 | .expect("we need an integer"); 22 | println!("generating genesis block! "); 23 | let mut chain = blockchain::Chain::new(miner_addr.trim().to_string(), diff); 24 | 25 | loop { 26 | println!("Menu"); 27 | println!("1) New Transaction"); 28 | println!("2) Mine block"); 29 | println!("3) Change Difficulty"); 30 | println!("4) Change Reward"); 31 | println!("0) Exit"); 32 | print!("Enter your choice: "); 33 | io::stdout().flush(); 34 | choice.clear(); 35 | io::stdin().read_line(&mut choice); 36 | println!(""); 37 | 38 | match choice.trim().parse().unwrap() { 39 | 0 => { 40 | println!("exiting!"); 41 | process::exit(0); 42 | } 43 | 1 => { 44 | let mut sender = String::new(); 45 | let mut receiver = String::new(); 46 | let mut amount = String::new(); 47 | 48 | print!("enter sender address:"); 49 | io::stdout().flush(); 50 | io::stdin().read_line(&mut sender); 51 | print!("enter receiver address: "); 52 | io::stdout().flush(); 53 | io::stdin().read_line(&mut receiver); 54 | print!("Enter amount: "); 55 | io::stdout().flush(); 56 | io::stdin().read_line(&mut amount); 57 | 58 | let res = chain.new_transaction( 59 | sender.trim().to_string(), 60 | receiver.trim().to_string(), 61 | amount.trim().parse().unwrap(), 62 | ); 63 | 64 | match res { 65 | true => println!("transaction added"), 66 | false => println!("transaction failed"), 67 | } 68 | } 69 | 2 => { 70 | println!("Generating block"); 71 | let res = chain.generate_new_block(); 72 | match res { 73 | true => println!("Block generated successfully"), 74 | false => println!("Block generation failed"), 75 | } 76 | } 77 | 3 => { 78 | let mut new_diff = String::new(); 79 | print!("enter new difficulty: "); 80 | io::stdout().flush(); 81 | io::stdin().read_line(&mut new_diff); 82 | let res = chain.update_difficulty(new_diff.trim().parse().unwrap()); 83 | match res { 84 | true => println!("Updated Difficulty"), 85 | false => println!("Failed Update Difficulty"), 86 | } 87 | } 88 | 4 => { 89 | let mut new_reward = String::new(); 90 | print!("Enter new reward: "); 91 | io::stdout().flush(); 92 | io::stdin().read_line(&mut new_reward); 93 | let res = chain.update_reward(new_reward.trim().parse().unwrap()); 94 | match res { 95 | true => println!("Updated reward"), 96 | false => println!("Failed Update reward"), 97 | } 98 | } 99 | _ => println!("Invalid option please retry"), 100 | } 101 | } 102 | } 103 | --------------------------------------------------------------------------------