├── .gitignore ├── Cargo.toml ├── README.md ├── Screenshot20220105125717.png ├── merkle_tree.jpg └── src ├── block.rs ├── blockchain.rs ├── cli.rs ├── errors.rs ├── main.rs ├── server.rs ├── transaction.rs ├── tx.rs ├── utxoset.rs └── wallets.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | Cargo.lock 4 | data 5 | 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blockchain-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | sha2 = "0.10.6" 10 | rust-crypto = "^0.2" 11 | bincode = "1.3" 12 | failure = "0.1" 13 | sled = "0.34" 14 | log = "0.4" 15 | env_logger = "0.10.0" 16 | clap = "4.0.29" 17 | bitcoincash-addr = "0.5.2" 18 | rand = "0.8.5" 19 | merkle-cbt = "0.3.2" 20 | serde = {version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | a simple blockchain demo for learning 2 | 3 | 4 | # blockchain-rust - 5 | 6 | 7 | a simple blockchain demo for learning 8 | 9 | 10 | ## usage 11 | 12 | - Create wallet: 13 | ```sh 14 | cargo run createwallet 15 | ``` 16 | - Create blockchain: 17 | ``` 18 | cargo run create
19 | ``` 20 | - send coins (if `-m` is specified, the block will be mined immediately in the same node): 21 | ``` 22 | cargo run send -m 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /Screenshot20220105125717.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/behrouz-rfa/blockchain-rust/75ce1573eb2e4cec393d901fb1cf8a9d41168ca4/Screenshot20220105125717.png -------------------------------------------------------------------------------- /merkle_tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/behrouz-rfa/blockchain-rust/75ce1573eb2e4cec393d901fb1cf8a9d41168ca4/merkle_tree.jpg -------------------------------------------------------------------------------- /src/block.rs: -------------------------------------------------------------------------------- 1 | //! Block implement of blockchain 2 | 3 | use super::*; 4 | use crate::transaction::Transaction; 5 | use bincode::serialize; 6 | use crypto::digest::Digest; 7 | use crypto::sha2::Sha256; 8 | use merkle_cbt::merkle_tree::Merge; 9 | use merkle_cbt::merkle_tree::CBMT; 10 | use serde::{Deserialize, Serialize}; 11 | use std::time::SystemTime; 12 | use log::info; 13 | 14 | const TARGET_HEXS: usize = 4; 15 | 16 | /// Block keeps block headers 17 | #[derive(Serialize, Deserialize, Debug, Clone)] 18 | pub struct Block { 19 | timestamp: u128, 20 | transactions: Vec, 21 | prev_block_hash: String, 22 | hash: String, 23 | nonce: i32, 24 | height: i32, 25 | } 26 | 27 | impl Block { 28 | pub fn get_hash(&self) -> String { 29 | self.hash.clone() 30 | } 31 | 32 | pub fn get_prev_hash(&self) -> String { 33 | self.prev_block_hash.clone() 34 | } 35 | 36 | pub fn get_transaction(&self) -> &Vec { 37 | &self.transactions 38 | } 39 | 40 | pub fn get_height(&self) -> i32 { 41 | self.height 42 | } 43 | 44 | /// NewBlock creates and returns Block 45 | pub fn new_block( 46 | transactions: Vec, 47 | prev_block_hash: String, 48 | height: i32, 49 | ) -> Result { 50 | let timestamp = SystemTime::now() 51 | .duration_since(SystemTime::UNIX_EPOCH)? 52 | .as_millis(); 53 | let mut block = Block { 54 | timestamp, 55 | transactions, 56 | prev_block_hash, 57 | hash: String::new(), 58 | nonce: 0, 59 | height, 60 | }; 61 | block.run_proof_of_work()?; 62 | Ok(block) 63 | } 64 | 65 | /// NewGenesisBlock creates and returns genesis Block 66 | pub fn new_genesis_block(coinbase: Transaction) -> Block { 67 | Block::new_block(vec![coinbase], String::new(), 0).unwrap() 68 | } 69 | 70 | /// Run performs a proof-of-work 71 | fn run_proof_of_work(&mut self) -> Result<()> { 72 | info!("Mining the block"); 73 | while !self.validate()? { 74 | self.nonce += 1; 75 | } 76 | let data = self.prepare_hash_data()?; 77 | let mut hasher = Sha256::new(); 78 | hasher.input(&data[..]); 79 | self.hash = hasher.result_str(); 80 | Ok(()) 81 | } 82 | 83 | /// HashTransactions returns a hash of the transactions in the block 84 | fn hash_transactions(&self) -> Result> { 85 | let mut transactions = Vec::new(); 86 | for tx in &self.transactions { 87 | transactions.push(tx.hash()?.as_bytes().to_owned()); 88 | } 89 | let tree = CBMT::, MergeVu8>::build_merkle_tree(&transactions); 90 | 91 | Ok(tree.root()) 92 | } 93 | 94 | fn prepare_hash_data(&self) -> Result> { 95 | let content = ( 96 | self.prev_block_hash.clone(), 97 | self.hash_transactions()?, 98 | self.timestamp, 99 | TARGET_HEXS, 100 | self.nonce, 101 | ); 102 | let bytes = serialize(&content)?; 103 | Ok(bytes) 104 | } 105 | 106 | /// Validate validates block's PoW 107 | fn validate(&self) -> Result { 108 | let data = self.prepare_hash_data()?; 109 | let mut hasher = Sha256::new(); 110 | hasher.input(&data[..]); 111 | let mut vec1: Vec = Vec::new(); 112 | vec1.resize(TARGET_HEXS, '0' as u8); 113 | Ok(&hasher.result_str()[0..TARGET_HEXS] == String::from_utf8(vec1)?) 114 | } 115 | } 116 | 117 | struct MergeVu8 {} 118 | 119 | impl Merge for MergeVu8 { 120 | type Item = Vec; 121 | fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item { 122 | let mut hasher = Sha256::new(); 123 | let mut data: Vec = left.clone(); 124 | data.append(&mut right.clone()); 125 | hasher.input(&data); 126 | let mut re: [u8; 32] = [0; 32]; 127 | hasher.result(&mut re); 128 | re.to_vec() 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/blockchain.rs: -------------------------------------------------------------------------------- 1 | //! Blockchain 2 | 3 | use super::*; 4 | use crate::block::*; 5 | use crate::transaction::*; 6 | use bincode::{deserialize, serialize}; 7 | use failure::format_err; 8 | use sled; 9 | use std::collections::HashMap; 10 | use log::{debug, info}; 11 | 12 | const GENESIS_COINBASE_DATA: &str = 13 | "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; 14 | 15 | /// Blockchain implements interactions with a DB 16 | #[derive(Debug)] 17 | pub struct Blockchain { 18 | pub tip: String, 19 | pub db: sled::Db, 20 | } 21 | 22 | /// BlockchainIterator is used to iterate over blockchain blocks 23 | pub struct BlockchainIterator<'a> { 24 | current_hash: String, 25 | bc: &'a Blockchain, 26 | } 27 | 28 | impl Blockchain { 29 | /// NewBlockchain creates a new Blockchain db 30 | pub fn new() -> Result { 31 | info!("open blockchain"); 32 | 33 | let db = sled::open("data/blocks")?; 34 | let hash = match db.get("LAST")? { 35 | Some(l) => l.to_vec(), 36 | None => Vec::new(), 37 | }; 38 | info!("Found block database"); 39 | let lasthash = if hash.is_empty() { 40 | String::new() 41 | } else { 42 | String::from_utf8(hash.to_vec())? 43 | }; 44 | Ok(Blockchain { tip: lasthash, db }) 45 | } 46 | 47 | /// CreateBlockchain creates a new blockchain DB 48 | pub fn create_blockchain(address: String) -> Result { 49 | info!("Creating new blockchain"); 50 | 51 | std::fs::remove_dir_all("data/blocks").ok(); 52 | let db = sled::open("data/blocks")?; 53 | debug!("Creating new block database"); 54 | let cbtx = Transaction::new_coinbase(address, String::from(GENESIS_COINBASE_DATA))?; 55 | let genesis: Block = Block::new_genesis_block(cbtx); 56 | db.insert(genesis.get_hash(), serialize(&genesis)?)?; 57 | db.insert("LAST", genesis.get_hash().as_bytes())?; 58 | let bc = Blockchain { 59 | tip: genesis.get_hash(), 60 | db, 61 | }; 62 | bc.db.flush()?; 63 | Ok(bc) 64 | } 65 | 66 | /// MineBlock mines a new block with the provided transactions 67 | pub fn mine_block(&mut self, transactions: Vec) -> Result { 68 | info!("mine a new block"); 69 | 70 | for tx in &transactions { 71 | if !self.verify_transacton(tx)? { 72 | return Err(format_err!("ERROR: Invalid transaction")); 73 | } 74 | } 75 | 76 | let lasthash = self.db.get("LAST")?.unwrap(); 77 | 78 | let newblock = Block::new_block( 79 | transactions, 80 | String::from_utf8(lasthash.to_vec())?, 81 | self.get_best_height()? + 1, 82 | )?; 83 | self.db.insert(newblock.get_hash(), serialize(&newblock)?)?; 84 | self.db.insert("LAST", newblock.get_hash().as_bytes())?; 85 | self.db.flush()?; 86 | 87 | self.tip = newblock.get_hash(); 88 | Ok(newblock) 89 | } 90 | 91 | /// Iterator returns a BlockchainIterat 92 | pub fn iter(&self) -> BlockchainIterator { 93 | BlockchainIterator { 94 | current_hash: self.tip.clone(), 95 | bc: &self, 96 | } 97 | } 98 | 99 | /// FindUTXO finds and returns all unspent transaction outputs 100 | pub fn find_UTXO(&self) -> HashMap { 101 | let mut utxos: HashMap = HashMap::new(); 102 | let mut spend_txos: HashMap> = HashMap::new(); 103 | 104 | for block in self.iter() { 105 | for tx in block.get_transaction() { 106 | for index in 0..tx.vout.len() { 107 | if let Some(ids) = spend_txos.get(&tx.id) { 108 | if ids.contains(&(index as i32)) { 109 | continue; 110 | } 111 | } 112 | 113 | match utxos.get_mut(&tx.id) { 114 | Some(v) => { 115 | v.outputs.push(tx.vout[index].clone()); 116 | } 117 | None => { 118 | utxos.insert( 119 | tx.id.clone(), 120 | TXOutputs { 121 | outputs: vec![tx.vout[index].clone()], 122 | }, 123 | ); 124 | } 125 | } 126 | } 127 | 128 | if !tx.is_coinbase() { 129 | for i in &tx.vin { 130 | match spend_txos.get_mut(&i.txid) { 131 | Some(v) => { 132 | v.push(i.vout); 133 | } 134 | None => { 135 | spend_txos.insert(i.txid.clone(), vec![i.vout]); 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | 143 | utxos 144 | } 145 | 146 | /// FindTransaction finds a transaction by its ID 147 | pub fn find_transacton(&self, id: &str) -> Result { 148 | for b in self.iter() { 149 | for tx in b.get_transaction() { 150 | if tx.id == id { 151 | return Ok(tx.clone()); 152 | } 153 | } 154 | } 155 | Err(format_err!("Transaction is not found")) 156 | } 157 | 158 | fn get_prev_TXs(&self, tx: &Transaction) -> Result> { 159 | let mut prev_TXs = HashMap::new(); 160 | for vin in &tx.vin { 161 | let prev_TX = self.find_transacton(&vin.txid)?; 162 | prev_TXs.insert(prev_TX.id.clone(), prev_TX); 163 | } 164 | Ok(prev_TXs) 165 | } 166 | 167 | /// SignTransaction signs inputs of a Transaction 168 | pub fn sign_transacton(&self, tx: &mut Transaction, private_key: &[u8]) -> Result<()> { 169 | let prev_TXs = self.get_prev_TXs(tx)?; 170 | tx.sign(private_key, prev_TXs)?; 171 | Ok(()) 172 | } 173 | 174 | /// VerifyTransaction verifies transaction input signatures 175 | pub fn verify_transacton(&self, tx: &Transaction) -> Result { 176 | if tx.is_coinbase() { 177 | return Ok(true); 178 | } 179 | let prev_TXs = self.get_prev_TXs(tx)?; 180 | tx.verify(prev_TXs) 181 | } 182 | 183 | /// AddBlock saves the block into the blockchain 184 | pub fn add_block(&mut self, block: Block) -> Result<()> { 185 | let data = serialize(&block)?; 186 | if let Some(_) = self.db.get(block.get_hash())? { 187 | return Ok(()); 188 | } 189 | self.db.insert(block.get_hash(), data)?; 190 | 191 | let lastheight = self.get_best_height()?; 192 | if block.get_height() > lastheight { 193 | self.db.insert("LAST", block.get_hash().as_bytes())?; 194 | self.tip = block.get_hash(); 195 | self.db.flush()?; 196 | } 197 | Ok(()) 198 | } 199 | 200 | // GetBlock finds a block by its hash and returns it 201 | pub fn get_block(&self, block_hash: &str) -> Result { 202 | let data = self.db.get(block_hash)?.unwrap(); 203 | let block = deserialize(&data.to_vec())?; 204 | Ok(block) 205 | } 206 | 207 | /// GetBestHeight returns the height of the latest block 208 | pub fn get_best_height(&self) -> Result { 209 | let lasthash = if let Some(h) = self.db.get("LAST")? { 210 | h 211 | } else { 212 | return Ok(-1); 213 | }; 214 | let last_data = self.db.get(lasthash)?.unwrap(); 215 | let last_block: Block = deserialize(&last_data.to_vec())?; 216 | Ok(last_block.get_height()) 217 | } 218 | 219 | /// GetBlockHashes returns a list of hashes of all the blocks in the chain 220 | pub fn get_block_hashs(&self) -> Vec { 221 | let mut list = Vec::new(); 222 | for b in self.iter() { 223 | list.push(b.get_hash()); 224 | } 225 | list 226 | } 227 | } 228 | 229 | impl<'a> Iterator for BlockchainIterator<'a> { 230 | type Item = Block; 231 | 232 | fn next(&mut self) -> Option { 233 | if let Ok(encoded_block) = self.bc.db.get(&self.current_hash) { 234 | return match encoded_block { 235 | Some(b) => { 236 | if let Ok(block) = deserialize::(&b) { 237 | self.current_hash = block.get_prev_hash(); 238 | Some(block) 239 | } else { 240 | None 241 | } 242 | } 243 | None => None, 244 | }; 245 | } 246 | None 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use std::process::exit; 2 | use bitcoincash_addr::Address; 3 | use clap::{arg, Command}; 4 | use crate::blockchain::Blockchain; 5 | use crate::errors::Result; 6 | use crate::server::Server; 7 | use crate::transaction::Transaction; 8 | use crate::utxoset::UTXOSet; 9 | use crate::wallets::{Wallet, Wallets}; 10 | 11 | pub struct Cli {} 12 | 13 | impl Cli { 14 | pub fn new() -> Result { 15 | Ok(Cli {}) 16 | } 17 | pub fn run(&mut self) -> Result<()> { 18 | let matches = Command::new("blockchain-rust-demo") 19 | .version("0.1") 20 | .author("behrouz.r.fa@gmail.com") 21 | .about("blockchain in rust: a simple blockchain for learning") 22 | .subcommand(Command::new("printchain").about("print all the chain blocks")) 23 | .subcommand(Command::new("createwallet").about("create a wallet")) 24 | .subcommand(Command::new("listaddresses").about("list all addresses")) 25 | .subcommand(Command::new("reindex").about("reindex UTXO")) 26 | .subcommand(Command::new("getbalance") 27 | .about("get balance in the blochain") 28 | .arg(arg!(
"'The Address it get balance for'")) 29 | ).subcommand(Command::new("startnode") 30 | .about("start the node server") 31 | .arg(arg!("'the port server bind to locally'")) 32 | ) 33 | .subcommand(Command::new("create").about("Create new blochain") 34 | .arg(arg!(
"'The address to send gensis block reqward to' ")) 35 | ) 36 | 37 | .subcommand( 38 | Command::new("send") 39 | .about("send in the blockchain") 40 | .arg(arg!(" 'Source wallet address'")) 41 | .arg(arg!(" 'Destination wallet address'")) 42 | .arg(arg!(" 'Destination wallet address'")) 43 | .arg(arg!(-m --mine " 'the from address mine immediately'")), 44 | ) 45 | .subcommand( 46 | Command::new("startminer") 47 | .about("start the minner server") 48 | .arg(arg!(" 'the port server bind to locally'")) 49 | .arg(arg!(
" 'wallet address'")), 50 | 51 | ) 52 | .get_matches(); 53 | 54 | if let Some(ref matches) = matches.subcommand_matches("startminer") { 55 | let port = if let Some(port) = matches.get_one::("PORT") { 56 | port 57 | } else { 58 | println!("PORT not supply!: usage"); 59 | exit(1) 60 | }; 61 | 62 | let address = if let Some(address) = matches.get_one::("ADDRESS") { 63 | address 64 | } else { 65 | println!("ADDRESS not supply!: usage"); 66 | exit(1) 67 | }; 68 | let bc = Blockchain::new()?; 69 | let utxo_set = UTXOSet { blockchain: bc }; 70 | let server = Server::new(port, address, utxo_set)?; 71 | server.start_server()?; 72 | } 73 | 74 | 75 | if let Some(ref matches) = matches.subcommand_matches("startnode") { 76 | if let Some(port) = matches.get_one::("PORT") { 77 | let bc = Blockchain::new()?; 78 | let utxo_set = UTXOSet { blockchain: bc }; 79 | let server = Server::new(port, "", utxo_set)?; 80 | server.start_server()?; 81 | } 82 | } 83 | 84 | if let Some(_) = matches.subcommand_matches("createwallet") { 85 | println!("address: {}", cmd_create_wallet()?); 86 | } 87 | if let Some(_) = matches.subcommand_matches("reindex") { 88 | let count = cmd_reindex()?; 89 | println!("Done! There are {} transactions in the UTXO set.", count); 90 | } 91 | 92 | if let Some(_) = matches.subcommand_matches("listaddresses") { 93 | cmd_list_address()?; 94 | } 95 | 96 | if let Some(ref matches) = matches.subcommand_matches("create") { 97 | if let Some(address) = matches.get_one::("ADDRESS") { 98 | cmd_create_blockchain(address)?; 99 | } 100 | 101 | } 102 | 103 | 104 | if let Some(ref matches) = matches.subcommand_matches("getbalance") { 105 | if let Some(address) = matches.get_one::("ADDRESS") { 106 | let balance = cmd_get_balance(address)?; 107 | println!("Balance: {}\n", balance); 108 | } 109 | } 110 | 111 | if let Some(ref matches) = matches.subcommand_matches("send") { 112 | let from = if let Some(address) = matches.get_one::("FROM") { 113 | address 114 | } else { 115 | println!("from not supply!: usage"); 116 | exit(1) 117 | }; 118 | 119 | let to = if let Some(address) = matches.get_one::("TO") { 120 | address 121 | } else { 122 | println!("from not supply!: usage"); 123 | exit(1) 124 | }; 125 | 126 | let amount: i32 = if let Some(amount) = matches.get_one::("AMOUNT") { 127 | amount.parse()? 128 | } else { 129 | println!("from not supply!: usage"); 130 | exit(1) 131 | }; 132 | 133 | if matches.contains_id("mine") { 134 | cmd_send(from, to, amount, true)?; 135 | } else { 136 | cmd_send(from, to, amount, false)?; 137 | } 138 | 139 | 140 | /*else { 141 | println!("Not printing testing lists..."); 142 | }*/ 143 | } 144 | 145 | if let Some(_) = matches.subcommand_matches("printchain") { 146 | cmd_print_chain()?; 147 | } 148 | 149 | Ok(()) 150 | } 151 | } 152 | 153 | fn cmd_send(from: &str, to: &str, amount: i32, mine_now: bool) -> Result<()> { 154 | let bc = Blockchain::new()?; 155 | let mut utxo_set = UTXOSet { blockchain: bc }; 156 | let wallets = Wallets::new()?; 157 | let wallet = wallets.get_wallet(from).unwrap(); 158 | let tx = Transaction::new_UTXO(wallet, to, amount, &utxo_set)?; 159 | if mine_now { 160 | let cbtx = Transaction::new_coinbase(from.to_string(), String::from("reward!"))?; 161 | let new_block = utxo_set.blockchain.mine_block(vec![cbtx, tx])?; 162 | 163 | utxo_set.update(&new_block)?; 164 | } else { 165 | Server::send_transaction(&tx, utxo_set)?; 166 | } 167 | 168 | println!("success!"); 169 | Ok(()) 170 | } 171 | 172 | fn cmd_create_wallet() -> Result { 173 | let mut ws = Wallets::new()?; 174 | let address = ws.create_wallet(); 175 | ws.save_all()?; 176 | Ok(address) 177 | } 178 | 179 | fn cmd_reindex() -> Result { 180 | let bc = Blockchain::new()?; 181 | let utxo_set = UTXOSet { blockchain: bc }; 182 | utxo_set.reindex()?; 183 | utxo_set.count_transactions() 184 | } 185 | 186 | fn cmd_create_blockchain(address: &str) -> Result<()> { 187 | let address = String::from(address); 188 | let bc = Blockchain::create_blockchain(address)?; 189 | 190 | let utxo_set = UTXOSet { blockchain: bc }; 191 | utxo_set.reindex()?; 192 | println!("create blockchain"); 193 | Ok(()) 194 | } 195 | 196 | fn cmd_get_balance(address: &str) -> Result { 197 | let pub_key_hash = Address::decode(address).unwrap().body; 198 | let bc = Blockchain::new()?; 199 | let utxo_set = UTXOSet { blockchain: bc }; 200 | let utxos = utxo_set.find_UTXO(&pub_key_hash)?; 201 | 202 | let mut balance = 0; 203 | for out in utxos.outputs { 204 | balance += out.value; 205 | } 206 | Ok(balance) 207 | } 208 | 209 | fn cmd_print_chain() -> Result<()> { 210 | let bc = Blockchain::new()?; 211 | for b in bc.iter() { 212 | println!("{:#?}", b); 213 | } 214 | Ok(()) 215 | } 216 | 217 | fn cmd_list_address() -> Result<()> { 218 | let ws = Wallets::new()?; 219 | let addresses = ws.get_all_addresses(); 220 | println!("addresses: "); 221 | for ad in addresses { 222 | println!("{}", ad); 223 | } 224 | Ok(()) 225 | } -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | pub type Result = std::result::Result; 4 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::cli::Cli; 2 | use crate::errors::Result; 3 | 4 | mod block; 5 | 6 | mod errors; 7 | mod blockchain; 8 | mod cli; 9 | mod transaction; 10 | mod wallets; 11 | mod tx; 12 | mod utxoset; 13 | mod server; 14 | 15 | 16 | fn main()->Result<()> { 17 | let mut cli = Cli::new()?; 18 | cli.run()?; 19 | 20 | Ok(()) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/server.rs: -------------------------------------------------------------------------------- 1 | //! server of Blockchain 2 | 3 | use super::*; 4 | use crate::block::*; 5 | use crate::transaction::*; 6 | use crate::utxoset::*; 7 | use bincode::{deserialize, serialize}; 8 | use failure::format_err; 9 | use serde::{Deserialize, Serialize}; 10 | use std::collections::{HashMap, HashSet}; 11 | use std::io::prelude::*; 12 | use std::net::{TcpListener, TcpStream}; 13 | use std::sync::*; 14 | use std::thread; 15 | use std::time::Duration; 16 | use log::{debug, info}; 17 | 18 | #[derive(Serialize, Deserialize, Debug, Clone)] 19 | enum Message { 20 | Addr(Vec), 21 | Version(Versionmsg), 22 | Tx(Txmsg), 23 | GetData(GetDatamsg), 24 | GetBlock(GetBlocksmsg), 25 | Inv(Invmsg), 26 | Block(Blockmsg), 27 | } 28 | 29 | #[derive(Serialize, Deserialize, Debug, Clone)] 30 | struct Blockmsg { 31 | addr_from: String, 32 | block: Block, 33 | } 34 | 35 | #[derive(Serialize, Deserialize, Debug, Clone)] 36 | struct GetBlocksmsg { 37 | addr_from: String, 38 | } 39 | 40 | #[derive(Serialize, Deserialize, Debug, Clone)] 41 | struct GetDatamsg { 42 | addr_from: String, 43 | kind: String, 44 | id: String, 45 | } 46 | 47 | #[derive(Serialize, Deserialize, Debug, Clone)] 48 | struct Invmsg { 49 | addr_from: String, 50 | kind: String, 51 | items: Vec, 52 | } 53 | 54 | #[derive(Serialize, Deserialize, Debug, Clone)] 55 | struct Txmsg { 56 | addr_from: String, 57 | transaction: Transaction, 58 | } 59 | 60 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 61 | struct Versionmsg { 62 | addr_from: String, 63 | version: i32, 64 | best_height: i32, 65 | } 66 | 67 | pub struct Server { 68 | node_address: String, 69 | mining_address: String, 70 | inner: Arc>, 71 | } 72 | 73 | struct ServerInner { 74 | known_nodes: HashSet, 75 | utxo: UTXOSet, 76 | blocks_in_transit: Vec, 77 | mempool: HashMap, 78 | } 79 | 80 | const KNOWN_NODE1: &str = "localhost:3000"; 81 | const CMD_LEN: usize = 12; 82 | const VERSION: i32 = 1; 83 | 84 | impl Server { 85 | pub fn new(port: &str, miner_address: &str, utxo: UTXOSet) -> Result { 86 | let mut node_set = HashSet::new(); 87 | node_set.insert(String::from(KNOWN_NODE1)); 88 | Ok(Server { 89 | node_address: String::from("localhost:") + port, 90 | mining_address: miner_address.to_string(), 91 | inner: Arc::new(Mutex::new(ServerInner { 92 | known_nodes: node_set, 93 | utxo, 94 | blocks_in_transit: Vec::new(), 95 | mempool: HashMap::new(), 96 | })), 97 | }) 98 | } 99 | 100 | pub fn start_server(&self) -> Result<()> { 101 | let server1 = Server { 102 | node_address: self.node_address.clone(), 103 | mining_address: self.mining_address.clone(), 104 | inner: Arc::clone(&self.inner), 105 | }; 106 | info!( 107 | "Start server at {}, minning address: {}", 108 | &self.node_address, &self.mining_address 109 | ); 110 | 111 | thread::spawn(move || { 112 | thread::sleep(Duration::from_millis(1000)); 113 | if server1.get_best_height()? == -1 { 114 | server1.request_blocks() 115 | } else { 116 | server1.send_version(KNOWN_NODE1) 117 | } 118 | }); 119 | 120 | let listener = TcpListener::bind(&self.node_address).unwrap(); 121 | info!("Server listen..."); 122 | 123 | for stream in listener.incoming() { 124 | let stream = stream?; 125 | let server1 = Server { 126 | node_address: self.node_address.clone(), 127 | mining_address: self.mining_address.clone(), 128 | inner: Arc::clone(&self.inner), 129 | }; 130 | thread::spawn(move || server1.handle_connection(stream)); 131 | } 132 | 133 | Ok(()) 134 | } 135 | 136 | pub fn send_transaction(tx: &Transaction, utxoset: UTXOSet) -> Result<()> { 137 | let server = Server::new("7000", "", utxoset)?; 138 | server.send_tx(KNOWN_NODE1, tx)?; 139 | Ok(()) 140 | } 141 | 142 | /* ------------------- inner halp functions ----------------------------------*/ 143 | 144 | fn remove_node(&self, addr: &str) { 145 | self.inner.lock().unwrap().known_nodes.remove(addr); 146 | } 147 | 148 | fn add_nodes(&self, addr: &str) { 149 | self.inner 150 | .lock() 151 | .unwrap() 152 | .known_nodes 153 | .insert(String::from(addr)); 154 | } 155 | 156 | fn get_known_nodes(&self) -> HashSet { 157 | self.inner.lock().unwrap().known_nodes.clone() 158 | } 159 | 160 | fn node_is_known(&self, addr: &str) -> bool { 161 | self.inner.lock().unwrap().known_nodes.get(addr).is_some() 162 | } 163 | 164 | fn replace_in_transit(&self, hashs: Vec) { 165 | let bit = &mut self.inner.lock().unwrap().blocks_in_transit; 166 | bit.clone_from(&hashs); 167 | } 168 | 169 | fn get_in_transit(&self) -> Vec { 170 | self.inner.lock().unwrap().blocks_in_transit.clone() 171 | } 172 | 173 | fn get_mempool_tx(&self, addr: &str) -> Option { 174 | match self.inner.lock().unwrap().mempool.get(addr) { 175 | Some(tx) => Some(tx.clone()), 176 | None => None, 177 | } 178 | } 179 | 180 | fn get_mempool(&self) -> HashMap { 181 | self.inner.lock().unwrap().mempool.clone() 182 | } 183 | 184 | fn insert_mempool(&self, tx: Transaction) { 185 | self.inner.lock().unwrap().mempool.insert(tx.id.clone(), tx); 186 | } 187 | 188 | fn clear_mempool(&self) { 189 | self.inner.lock().unwrap().mempool.clear() 190 | } 191 | 192 | fn get_best_height(&self) -> Result { 193 | self.inner.lock().unwrap().utxo.blockchain.get_best_height() 194 | } 195 | 196 | fn get_block_hashs(&self) -> Vec { 197 | self.inner.lock().unwrap().utxo.blockchain.get_block_hashs() 198 | } 199 | 200 | fn get_block(&self, block_hash: &str) -> Result { 201 | self.inner 202 | .lock() 203 | .unwrap() 204 | .utxo 205 | .blockchain 206 | .get_block(block_hash) 207 | } 208 | 209 | fn verify_tx(&self, tx: &Transaction) -> Result { 210 | self.inner 211 | .lock() 212 | .unwrap() 213 | .utxo 214 | .blockchain 215 | .verify_transacton(tx) 216 | } 217 | 218 | fn add_block(&self, block: Block) -> Result<()> { 219 | self.inner.lock().unwrap().utxo.blockchain.add_block(block) 220 | } 221 | 222 | fn mine_block(&self, txs: Vec) -> Result { 223 | self.inner.lock().unwrap().utxo.blockchain.mine_block(txs) 224 | } 225 | 226 | fn utxo_reindex(&self) -> Result<()> { 227 | self.inner.lock().unwrap().utxo.reindex() 228 | } 229 | 230 | /* -----------------------------------------------------*/ 231 | 232 | fn send_data(&self, addr: &str, data: &[u8]) -> Result<()> { 233 | if addr == &self.node_address { 234 | return Ok(()); 235 | } 236 | let mut stream = match TcpStream::connect(addr) { 237 | Ok(s) => s, 238 | Err(_) => { 239 | self.remove_node(addr); 240 | return Ok(()); 241 | } 242 | }; 243 | 244 | stream.write(data)?; 245 | 246 | info!("data send successfully"); 247 | Ok(()) 248 | } 249 | 250 | fn request_blocks(&self) -> Result<()> { 251 | for node in self.get_known_nodes() { 252 | self.send_get_blocks(&node)? 253 | } 254 | Ok(()) 255 | } 256 | 257 | fn send_block(&self, addr: &str, b: &Block) -> Result<()> { 258 | info!("send block data to: {} block hash: {}", addr, b.get_hash()); 259 | let data = Blockmsg { 260 | addr_from: self.node_address.clone(), 261 | block: b.clone(), 262 | }; 263 | let data = serialize(&(cmd_to_bytes("block"), data))?; 264 | self.send_data(addr, &data) 265 | } 266 | 267 | fn send_addr(&self, addr: &str) -> Result<()> { 268 | info!("send address info to: {}", addr); 269 | let nodes = self.get_known_nodes(); 270 | let data = serialize(&(cmd_to_bytes("addr"), nodes))?; 271 | self.send_data(addr, &data) 272 | } 273 | 274 | fn send_inv(&self, addr: &str, kind: &str, items: Vec) -> Result<()> { 275 | info!( 276 | "send inv message to: {} kind: {} data: {:?}", 277 | addr, kind, items 278 | ); 279 | let data = Invmsg { 280 | addr_from: self.node_address.clone(), 281 | kind: kind.to_string(), 282 | items, 283 | }; 284 | let data = serialize(&(cmd_to_bytes("inv"), data))?; 285 | self.send_data(addr, &data) 286 | } 287 | 288 | fn send_get_blocks(&self, addr: &str) -> Result<()> { 289 | info!("send get blocks message to: {}", addr); 290 | let data = GetBlocksmsg { 291 | addr_from: self.node_address.clone(), 292 | }; 293 | let data = serialize(&(cmd_to_bytes("getblocks"), data))?; 294 | self.send_data(addr, &data) 295 | } 296 | 297 | fn send_get_data(&self, addr: &str, kind: &str, id: &str) -> Result<()> { 298 | info!( 299 | "send get data message to: {} kind: {} id: {}", 300 | addr, kind, id 301 | ); 302 | let data = GetDatamsg { 303 | addr_from: self.node_address.clone(), 304 | kind: kind.to_string(), 305 | id: id.to_string(), 306 | }; 307 | let data = serialize(&(cmd_to_bytes("getdata"), data))?; 308 | self.send_data(addr, &data) 309 | } 310 | 311 | pub fn send_tx(&self, addr: &str, tx: &Transaction) -> Result<()> { 312 | info!("send tx to: {} txid: {}", addr, &tx.id); 313 | let data = Txmsg { 314 | addr_from: self.node_address.clone(), 315 | transaction: tx.clone(), 316 | }; 317 | let data = serialize(&(cmd_to_bytes("tx"), data))?; 318 | self.send_data(addr, &data) 319 | } 320 | 321 | fn send_version(&self, addr: &str) -> Result<()> { 322 | info!("send version info to: {}", addr); 323 | let data = Versionmsg { 324 | addr_from: self.node_address.clone(), 325 | best_height: self.get_best_height()?, 326 | version: VERSION, 327 | }; 328 | let data = serialize(&(cmd_to_bytes("version"), data))?; 329 | self.send_data(addr, &data) 330 | } 331 | 332 | fn handle_version(&self, msg: Versionmsg) -> Result<()> { 333 | info!("receive version msg: {:#?}", msg); 334 | let my_best_height = self.get_best_height()?; 335 | if my_best_height < msg.best_height { 336 | self.send_get_blocks(&msg.addr_from)?; 337 | } else if my_best_height > msg.best_height { 338 | self.send_version(&msg.addr_from)?; 339 | } 340 | 341 | self.send_addr(&msg.addr_from)?; 342 | 343 | if !self.node_is_known(&msg.addr_from) { 344 | self.add_nodes(&msg.addr_from); 345 | } 346 | Ok(()) 347 | } 348 | 349 | fn handle_addr(&self, msg: Vec) -> Result<()> { 350 | info!("receive address msg: {:#?}", msg); 351 | for node in msg { 352 | self.add_nodes(&node); 353 | } 354 | //self.request_blocks()?; 355 | Ok(()) 356 | } 357 | 358 | fn handle_block(&self, msg: Blockmsg) -> Result<()> { 359 | info!( 360 | "receive block msg: {}, {}", 361 | msg.addr_from, 362 | msg.block.get_hash() 363 | ); 364 | self.add_block(msg.block)?; 365 | 366 | let mut in_transit = self.get_in_transit(); 367 | if in_transit.len() > 0 { 368 | let block_hash = &in_transit[0]; 369 | self.send_get_data(&msg.addr_from, "block", block_hash)?; 370 | in_transit.remove(0); 371 | self.replace_in_transit(in_transit); 372 | } else { 373 | self.utxo_reindex()?; 374 | } 375 | 376 | Ok(()) 377 | } 378 | 379 | fn handle_inv(&self, msg: Invmsg) -> Result<()> { 380 | info!("receive inv msg: {:#?}", msg); 381 | if msg.kind == "block" { 382 | let block_hash = &msg.items[0]; 383 | self.send_get_data(&msg.addr_from, "block", block_hash)?; 384 | 385 | let mut new_in_transit = Vec::new(); 386 | for b in &msg.items { 387 | if b != block_hash { 388 | new_in_transit.push(b.clone()); 389 | } 390 | } 391 | self.replace_in_transit(new_in_transit); 392 | } else if msg.kind == "tx" { 393 | let txid = &msg.items[0]; 394 | match self.get_mempool_tx(txid) { 395 | Some(tx) => { 396 | if tx.id.is_empty() { 397 | self.send_get_data(&msg.addr_from, "tx", txid)? 398 | } 399 | } 400 | None => self.send_get_data(&msg.addr_from, "tx", txid)?, 401 | } 402 | } 403 | Ok(()) 404 | } 405 | 406 | fn handle_get_blocks(&self, msg: GetBlocksmsg) -> Result<()> { 407 | info!("receive get blocks msg: {:#?}", msg); 408 | let block_hashs = self.get_block_hashs(); 409 | self.send_inv(&msg.addr_from, "block", block_hashs)?; 410 | Ok(()) 411 | } 412 | 413 | fn handle_get_data(&self, msg: GetDatamsg) -> Result<()> { 414 | info!("receive get data msg: {:#?}", msg); 415 | if msg.kind == "block" { 416 | let block = self.get_block(&msg.id)?; 417 | self.send_block(&msg.addr_from, &block)?; 418 | } else if msg.kind == "tx" { 419 | let tx = self.get_mempool_tx(&msg.id).unwrap(); 420 | self.send_tx(&msg.addr_from, &tx)?; 421 | } 422 | Ok(()) 423 | } 424 | 425 | fn handle_tx(&self, msg: Txmsg) -> Result<()> { 426 | info!("receive tx msg: {} {}", msg.addr_from, &msg.transaction.id); 427 | self.insert_mempool(msg.transaction.clone()); 428 | 429 | let known_nodes = self.get_known_nodes(); 430 | if self.node_address == KNOWN_NODE1 { 431 | for node in known_nodes { 432 | if node != self.node_address && node != msg.addr_from { 433 | self.send_inv(&node, "tx", vec![msg.transaction.id.clone()])?; 434 | } 435 | } 436 | } else { 437 | let mut mempool = self.get_mempool(); 438 | debug!("Current mempool: {:#?}", &mempool); 439 | if mempool.len() >= 1 && !self.mining_address.is_empty() { 440 | loop { 441 | let mut txs = Vec::new(); 442 | 443 | for (_, tx) in &mempool { 444 | if self.verify_tx(tx)? { 445 | txs.push(tx.clone()); 446 | } 447 | } 448 | 449 | if txs.is_empty() { 450 | return Ok(()); 451 | } 452 | 453 | let cbtx = 454 | Transaction::new_coinbase(self.mining_address.clone(), String::new())?; 455 | txs.push(cbtx); 456 | 457 | for tx in &txs { 458 | mempool.remove(&tx.id); 459 | } 460 | 461 | let new_block = self.mine_block(txs)?; 462 | self.utxo_reindex()?; 463 | 464 | for node in self.get_known_nodes() { 465 | if node != self.node_address { 466 | self.send_inv(&node, "block", vec![new_block.get_hash()])?; 467 | } 468 | } 469 | 470 | if mempool.len() == 0 { 471 | break; 472 | } 473 | } 474 | self.clear_mempool(); 475 | } 476 | } 477 | 478 | Ok(()) 479 | } 480 | 481 | fn handle_connection(&self, mut stream: TcpStream) -> Result<()> { 482 | let mut buffer = Vec::new(); 483 | let count = stream.read_to_end(&mut buffer)?; 484 | info!("Accept request: length {}", count); 485 | 486 | let cmd = bytes_to_cmd(&buffer)?; 487 | 488 | match cmd { 489 | Message::Addr(data) => self.handle_addr(data)?, 490 | Message::Block(data) => self.handle_block(data)?, 491 | Message::Inv(data) => self.handle_inv(data)?, 492 | Message::GetBlock(data) => self.handle_get_blocks(data)?, 493 | Message::GetData(data) => self.handle_get_data(data)?, 494 | Message::Tx(data) => self.handle_tx(data)?, 495 | Message::Version(data) => self.handle_version(data)?, 496 | } 497 | 498 | Ok(()) 499 | } 500 | } 501 | 502 | fn cmd_to_bytes(cmd: &str) -> [u8; CMD_LEN] { 503 | let mut data = [0; CMD_LEN]; 504 | for (i, d) in cmd.as_bytes().iter().enumerate() { 505 | data[i] = *d; 506 | } 507 | data 508 | } 509 | 510 | fn bytes_to_cmd(bytes: &[u8]) -> Result { 511 | let mut cmd = Vec::new(); 512 | let cmd_bytes = &bytes[..CMD_LEN]; 513 | let data = &bytes[CMD_LEN..]; 514 | for b in cmd_bytes { 515 | if 0 as u8 != *b { 516 | cmd.push(*b); 517 | } 518 | } 519 | info!("cmd: {}", String::from_utf8(cmd.clone())?); 520 | 521 | if cmd == "addr".as_bytes() { 522 | let data: Vec = deserialize(data)?; 523 | Ok(Message::Addr(data)) 524 | } else if cmd == "block".as_bytes() { 525 | let data: Blockmsg = deserialize(data)?; 526 | Ok(Message::Block(data)) 527 | } else if cmd == "inv".as_bytes() { 528 | let data: Invmsg = deserialize(data)?; 529 | Ok(Message::Inv(data)) 530 | } else if cmd == "getblocks".as_bytes() { 531 | let data: GetBlocksmsg = deserialize(data)?; 532 | Ok(Message::GetBlock(data)) 533 | } else if cmd == "getdata".as_bytes() { 534 | let data: GetDatamsg = deserialize(data)?; 535 | Ok(Message::GetData(data)) 536 | } else if cmd == "tx".as_bytes() { 537 | let data: Txmsg = deserialize(data)?; 538 | Ok(Message::Tx(data)) 539 | } else if cmd == "version".as_bytes() { 540 | let data: Versionmsg = deserialize(data)?; 541 | Ok(Message::Version(data)) 542 | } else { 543 | Err(format_err!("Unknown command in the server")) 544 | } 545 | } 546 | 547 | #[cfg(test)] 548 | mod test { 549 | use super::*; 550 | use crate::blockchain::*; 551 | use crate::wallets::*; 552 | 553 | #[test] 554 | fn test_cmd() { 555 | let mut ws = Wallets::new().unwrap(); 556 | let wa1 = ws.create_wallet(); 557 | let bc = Blockchain::create_blockchain(wa1).unwrap(); 558 | let utxo_set = UTXOSet { blockchain: bc }; 559 | let server = Server::new("7878", "localhost:3001", utxo_set).unwrap(); 560 | 561 | let vmsg = Versionmsg { 562 | addr_from: server.node_address.clone(), 563 | best_height: server.get_best_height().unwrap(), 564 | version: VERSION, 565 | }; 566 | let data = serialize(&(cmd_to_bytes("version"), vmsg.clone())).unwrap(); 567 | if let Message::Version(v) = bytes_to_cmd(&data).unwrap() { 568 | assert_eq!(v, vmsg); 569 | } else { 570 | panic!("wrong!"); 571 | } 572 | } 573 | } 574 | -------------------------------------------------------------------------------- /src/transaction.rs: -------------------------------------------------------------------------------- 1 | //! transaction implement 2 | 3 | use super::*; 4 | use crate::utxoset::*; 5 | use crate::wallets::*; 6 | use bincode::serialize; 7 | use bitcoincash_addr::Address; 8 | use crypto::digest::Digest; 9 | use crypto::ed25519; 10 | use crypto::sha2::Sha256; 11 | use failure::format_err; 12 | use rand::{Rng, RngCore}; 13 | use serde::{Deserialize, Serialize}; 14 | use std::collections::HashMap; 15 | use log::{debug, error, info}; 16 | use rand::rngs::OsRng; 17 | 18 | const SUBSIDY: i32 = 10; 19 | 20 | /// TXInput represents a transaction input 21 | #[derive(Serialize, Deserialize, Debug, Clone)] 22 | pub struct TXInput { 23 | pub txid: String, 24 | pub vout: i32, 25 | pub signature: Vec, 26 | pub pub_key: Vec, 27 | } 28 | 29 | /// TXOutput represents a transaction output 30 | #[derive(Serialize, Deserialize, Debug, Clone)] 31 | pub struct TXOutput { 32 | pub value: i32, 33 | pub pub_key_hash: Vec, 34 | } 35 | 36 | // TXOutputs collects TXOutput 37 | #[derive(Serialize, Deserialize, Debug, Clone)] 38 | pub struct TXOutputs { 39 | pub outputs: Vec, 40 | } 41 | 42 | /// Transaction represents a Bitcoin transaction 43 | #[derive(Serialize, Deserialize, Debug, Clone)] 44 | pub struct Transaction { 45 | pub id: String, 46 | pub vin: Vec, 47 | pub vout: Vec, 48 | } 49 | 50 | impl Transaction { 51 | /// NewUTXOTransaction creates a new transaction 52 | pub fn new_UTXO(wallet: &Wallet, to: &str, amount: i32, utxo: &UTXOSet) -> Result { 53 | info!( 54 | "new UTXO Transaction from: {} to: {}", 55 | wallet.get_address(), 56 | to 57 | ); 58 | let mut vin = Vec::new(); 59 | 60 | let mut pub_key_hash = wallet.public_key.clone(); 61 | hash_pub_key(&mut pub_key_hash); 62 | 63 | let acc_v = utxo.find_spendable_outputs(&pub_key_hash, amount)?; 64 | 65 | if acc_v.0 < amount { 66 | error!("Not Enough balance"); 67 | return Err(format_err!( 68 | "Not Enough balance: current balance {}", 69 | acc_v.0 70 | )); 71 | } 72 | 73 | for tx in acc_v.1 { 74 | for out in tx.1 { 75 | let input = TXInput { 76 | txid: tx.0.clone(), 77 | vout: out, 78 | signature: Vec::new(), 79 | pub_key: wallet.public_key.clone(), 80 | }; 81 | vin.push(input); 82 | } 83 | } 84 | 85 | let mut vout = vec![TXOutput::new(amount, to.to_string())?]; 86 | if acc_v.0 > amount { 87 | vout.push(TXOutput::new(acc_v.0 - amount, wallet.get_address())?) 88 | } 89 | 90 | let mut tx = Transaction { 91 | id: String::new(), 92 | vin, 93 | vout, 94 | }; 95 | tx.id = tx.hash()?; 96 | utxo.blockchain 97 | .sign_transacton(&mut tx, &wallet.secret_key)?; 98 | Ok(tx) 99 | } 100 | 101 | /// NewCoinbaseTX creates a new coinbase transaction 102 | pub fn new_coinbase(to: String, mut data: String) -> Result { 103 | info!("new coinbase Transaction to: {}", to); 104 | let mut key: [u8; 32] = [0; 32]; 105 | if data.is_empty() { 106 | let mut rand = OsRng::default(); 107 | rand.fill_bytes(&mut key); 108 | data = format!("Reward to '{}'", to); 109 | } 110 | let mut pub_key = Vec::from(data.as_bytes()); 111 | pub_key.append(&mut Vec::from(key)); 112 | 113 | let mut tx = Transaction { 114 | id: String::new(), 115 | vin: vec![TXInput { 116 | txid: String::new(), 117 | vout: -1, 118 | signature: Vec::new(), 119 | pub_key, 120 | }], 121 | vout: vec![TXOutput::new(SUBSIDY, to)?], 122 | }; 123 | tx.id = tx.hash()?; 124 | Ok(tx) 125 | } 126 | 127 | /// IsCoinbase checks whether the transaction is coinbase 128 | pub fn is_coinbase(&self) -> bool { 129 | self.vin.len() == 1 && self.vin[0].txid.is_empty() && self.vin[0].vout == -1 130 | } 131 | 132 | /// Verify verifies signatures of Transaction inputs 133 | pub fn verify(&self, prev_TXs: HashMap) -> Result { 134 | if self.is_coinbase() { 135 | return Ok(true); 136 | } 137 | 138 | for vin in &self.vin { 139 | if prev_TXs.get(&vin.txid).unwrap().id.is_empty() { 140 | return Err(format_err!("ERROR: Previous transaction is not correct")); 141 | } 142 | } 143 | 144 | let mut tx_copy = self.trim_copy(); 145 | 146 | for in_id in 0..self.vin.len() { 147 | let prev_Tx = prev_TXs.get(&self.vin[in_id].txid).unwrap(); 148 | tx_copy.vin[in_id].signature.clear(); 149 | tx_copy.vin[in_id].pub_key = prev_Tx.vout[self.vin[in_id].vout as usize] 150 | .pub_key_hash 151 | .clone(); 152 | tx_copy.id = tx_copy.hash()?; 153 | tx_copy.vin[in_id].pub_key = Vec::new(); 154 | 155 | if !ed25519::verify( 156 | &tx_copy.id.as_bytes(), 157 | &self.vin[in_id].pub_key, 158 | &self.vin[in_id].signature, 159 | ) { 160 | return Ok(false); 161 | } 162 | } 163 | 164 | Ok(true) 165 | } 166 | 167 | /// Sign signs each input of a Transaction 168 | pub fn sign( 169 | &mut self, 170 | private_key: &[u8], 171 | prev_TXs: HashMap, 172 | ) -> Result<()> { 173 | if self.is_coinbase() { 174 | return Ok(()); 175 | } 176 | 177 | for vin in &self.vin { 178 | if prev_TXs.get(&vin.txid).unwrap().id.is_empty() { 179 | return Err(format_err!("ERROR: Previous transaction is not correct")); 180 | } 181 | } 182 | 183 | let mut tx_copy = self.trim_copy(); 184 | 185 | for in_id in 0..tx_copy.vin.len() { 186 | let prev_Tx = prev_TXs.get(&tx_copy.vin[in_id].txid).unwrap(); 187 | tx_copy.vin[in_id].signature.clear(); 188 | tx_copy.vin[in_id].pub_key = prev_Tx.vout[tx_copy.vin[in_id].vout as usize] 189 | .pub_key_hash 190 | .clone(); 191 | tx_copy.id = tx_copy.hash()?; 192 | tx_copy.vin[in_id].pub_key = Vec::new(); 193 | let signature = ed25519::signature(tx_copy.id.as_bytes(), private_key); 194 | self.vin[in_id].signature = signature.to_vec(); 195 | } 196 | 197 | Ok(()) 198 | } 199 | 200 | /// Hash returns the hash of the Transaction 201 | pub fn hash(&self) -> Result { 202 | let mut copy = self.clone(); 203 | copy.id = String::new(); 204 | let data = serialize(©)?; 205 | let mut hasher = Sha256::new(); 206 | hasher.input(&data[..]); 207 | Ok(hasher.result_str()) 208 | } 209 | 210 | /// TrimmedCopy creates a trimmed copy of Transaction to be used in signing 211 | fn trim_copy(&self) -> Transaction { 212 | let mut vin = Vec::new(); 213 | let mut vout = Vec::new(); 214 | 215 | for v in &self.vin { 216 | vin.push(TXInput { 217 | txid: v.txid.clone(), 218 | vout: v.vout.clone(), 219 | signature: Vec::new(), 220 | pub_key: Vec::new(), 221 | }) 222 | } 223 | 224 | for v in &self.vout { 225 | vout.push(TXOutput { 226 | value: v.value, 227 | pub_key_hash: v.pub_key_hash.clone(), 228 | }) 229 | } 230 | 231 | Transaction { 232 | id: self.id.clone(), 233 | vin, 234 | vout, 235 | } 236 | } 237 | } 238 | 239 | impl TXOutput { 240 | /// IsLockedWithKey checks if the output can be used by the owner of the pubkey 241 | pub fn is_locked_with_key(&self, pub_key_hash: &[u8]) -> bool { 242 | self.pub_key_hash == pub_key_hash 243 | } 244 | /// Lock signs the output 245 | fn lock(&mut self, address: &str) -> Result<()> { 246 | let pub_key_hash = Address::decode(address).unwrap().body; 247 | debug!("lock: {}", address); 248 | self.pub_key_hash = pub_key_hash; 249 | Ok(()) 250 | } 251 | 252 | pub fn new(value: i32, address: String) -> Result { 253 | let mut txo = TXOutput { 254 | value, 255 | pub_key_hash: Vec::new(), 256 | }; 257 | txo.lock(&address)?; 258 | Ok(txo) 259 | } 260 | } 261 | 262 | #[cfg(test)] 263 | mod test { 264 | use super::*; 265 | 266 | #[test] 267 | fn test_signature() { 268 | let mut ws = Wallets::new().unwrap(); 269 | let wa1 = ws.create_wallet(); 270 | let w = ws.get_wallet(&wa1).unwrap().clone(); 271 | ws.save_all().unwrap(); 272 | drop(ws); 273 | 274 | let data = String::from("test"); 275 | let tx = Transaction::new_coinbase(wa1, data).unwrap(); 276 | assert!(tx.is_coinbase()); 277 | 278 | let signature = ed25519::signature(tx.id.as_bytes(), &w.secret_key); 279 | assert!(ed25519::verify(tx.id.as_bytes(), &w.public_key, &signature)); 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/tx.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use bitcoincash_addr::Address; 3 | use failure::format_err; 4 | use log::debug; 5 | use serde::{Serialize, Deserialize}; 6 | use crate::transaction::{Transaction}; 7 | use crate::errors::Result; 8 | use crate::wallets::hash_pub_key; 9 | // TXOutputs collects TXOutput 10 | #[derive(Serialize, Deserialize, Debug, Clone)] 11 | pub struct TXOutputs { 12 | pub outputs: Vec, 13 | } 14 | 15 | /// TXInput represents a transaction input 16 | #[derive(Serialize, Deserialize, Debug, Clone)] 17 | pub struct TXInput { 18 | pub txid: String, 19 | pub vout: i32, 20 | pub signature: Vec, 21 | pub pub_key: Vec, 22 | } 23 | 24 | /// TXOutput represents a transaction output 25 | #[derive(Serialize, Deserialize, Debug, Clone)] 26 | pub struct TXOutput { 27 | pub value: i32, 28 | pub pub_key_hash: Vec, 29 | } 30 | impl TXInput { 31 | /// CanUnlockOutputWith checks whether the address initiated the transaction 32 | pub fn can_unlock_output_with(&self, unlocking_data: &[u8]) -> bool { 33 | let mut pubkeyhash = self.pub_key.clone(); 34 | hash_pub_key(&mut pubkeyhash); 35 | pubkeyhash == unlocking_data 36 | } 37 | 38 | 39 | 40 | } 41 | 42 | impl TXOutput { 43 | /// CanBeUnlockedWith checks if the output can be unlocked with the provided data 44 | pub fn can_be_unlock_with(&self, unlocking_data: &[u8]) -> bool { 45 | self.pub_key_hash == unlocking_data 46 | } 47 | 48 | /// Lock signs the output 49 | fn lock(&mut self, address: &str) -> Result<()> { 50 | let pub_key_hash = Address::decode(address).unwrap().body; 51 | debug!("lock: {}", address); 52 | self.pub_key_hash = pub_key_hash; 53 | Ok(()) 54 | } 55 | 56 | pub fn new(value: i32, address: String) -> Result { 57 | let mut txo = TXOutput { 58 | value, 59 | pub_key_hash: Vec::new(), 60 | }; 61 | txo.lock(&address)?; 62 | Ok(txo) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/utxoset.rs: -------------------------------------------------------------------------------- 1 | //! unspend transaction output set 2 | 3 | use super::*; 4 | use crate::block::*; 5 | use crate::blockchain::*; 6 | use crate::transaction::*; 7 | use bincode::{deserialize, serialize}; 8 | use sled; 9 | use std::collections::HashMap; 10 | 11 | /// UTXOSet represents UTXO set 12 | pub struct UTXOSet { 13 | pub blockchain: Blockchain, 14 | } 15 | 16 | impl UTXOSet { 17 | /// FindUnspentTransactions returns a list of transactions containing unspent outputs 18 | pub fn find_spendable_outputs( 19 | &self, 20 | pub_key_hash: &[u8], 21 | amount: i32, 22 | ) -> Result<(i32, HashMap>)> { 23 | let mut unspent_outputs: HashMap> = HashMap::new(); 24 | let mut accumulated = 0; 25 | 26 | let db = sled::open("data/utxos")?; 27 | for kv in db.iter() { 28 | let (k, v) = kv?; 29 | let txid = String::from_utf8(k.to_vec())?; 30 | let outs: TXOutputs = deserialize(&v.to_vec())?; 31 | 32 | for out_idx in 0..outs.outputs.len() { 33 | if outs.outputs[out_idx].is_locked_with_key(pub_key_hash) && accumulated < amount { 34 | accumulated += outs.outputs[out_idx].value; 35 | match unspent_outputs.get_mut(&txid) { 36 | Some(v) => v.push(out_idx as i32), 37 | None => { 38 | unspent_outputs.insert(txid.clone(), vec![out_idx as i32]); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | Ok((accumulated, unspent_outputs)) 46 | } 47 | 48 | /// FindUTXO finds UTXO for a public key hash 49 | pub fn find_UTXO(&self, pub_key_hash: &[u8]) -> Result { 50 | let mut utxos = TXOutputs { 51 | outputs: Vec::new(), 52 | }; 53 | let db = sled::open("data/utxos")?; 54 | 55 | for kv in db.iter() { 56 | let (_, v) = kv?; 57 | let outs: TXOutputs = deserialize(&v.to_vec())?; 58 | 59 | for out in outs.outputs { 60 | if out.is_locked_with_key(pub_key_hash) { 61 | utxos.outputs.push(out.clone()) 62 | } 63 | } 64 | } 65 | 66 | Ok(utxos) 67 | } 68 | 69 | /// CountTransactions returns the number of transactions in the UTXO set 70 | pub fn count_transactions(&self) -> Result { 71 | let mut counter = 0; 72 | let db = sled::open("data/utxos")?; 73 | for kv in db.iter() { 74 | kv?; 75 | counter += 1; 76 | } 77 | Ok(counter) 78 | } 79 | 80 | /// Reindex rebuilds the UTXO set 81 | pub fn reindex(&self) -> Result<()> { 82 | std::fs::remove_dir_all("data/utxos").ok(); 83 | let db = sled::open("data/utxos")?; 84 | 85 | let utxos = self.blockchain.find_UTXO(); 86 | 87 | for (txid, outs) in utxos { 88 | db.insert(txid.as_bytes(), serialize(&outs)?)?; 89 | } 90 | 91 | Ok(()) 92 | } 93 | 94 | /// Update updates the UTXO set with transactions from the Block 95 | /// 96 | /// The Block is considered to be the tip of a blockchain 97 | pub fn update(&self, block: &Block) -> Result<()> { 98 | let db = sled::open("data/utxos")?; 99 | 100 | for tx in block.get_transaction() { 101 | if !tx.is_coinbase() { 102 | for vin in &tx.vin { 103 | let mut update_outputs = TXOutputs { 104 | outputs: Vec::new(), 105 | }; 106 | let outs: TXOutputs = deserialize(&db.get(&vin.txid)?.unwrap().to_vec())?; 107 | for out_idx in 0..outs.outputs.len() { 108 | if out_idx != vin.vout as usize { 109 | update_outputs.outputs.push(outs.outputs[out_idx].clone()); 110 | } 111 | } 112 | 113 | if update_outputs.outputs.is_empty() { 114 | db.remove(&vin.txid)?; 115 | } else { 116 | db.insert(vin.txid.as_bytes(), serialize(&update_outputs)?)?; 117 | } 118 | } 119 | } 120 | 121 | let mut new_outputs = TXOutputs { 122 | outputs: Vec::new(), 123 | }; 124 | for out in &tx.vout { 125 | new_outputs.outputs.push(out.clone()); 126 | } 127 | 128 | db.insert(tx.id.as_bytes(), serialize(&new_outputs)?)?; 129 | } 130 | Ok(()) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/wallets.rs: -------------------------------------------------------------------------------- 1 | //! bitcoin wallet 2 | 3 | use super::*; 4 | use bincode::{deserialize, serialize}; 5 | use bitcoincash_addr::*; 6 | use crypto::digest::Digest; 7 | use crypto::ed25519; 8 | use crypto::ripemd160::Ripemd160; 9 | use crypto::sha2::Sha256; 10 | use rand::{Rng, RngCore}; 11 | use serde::{Deserialize, Serialize}; 12 | use sled; 13 | use std::collections::HashMap; 14 | use log::info; 15 | use rand::rngs::OsRng; 16 | 17 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 18 | pub struct Wallet { 19 | pub secret_key: Vec, 20 | pub public_key: Vec, 21 | } 22 | 23 | impl Wallet { 24 | /// NewWallet creates and returns a Wallet 25 | fn new() -> Self { 26 | let mut key: [u8; 32] = [0; 32]; 27 | let mut rand = OsRng::default(); 28 | rand.fill_bytes(&mut key); 29 | let (secret_key, public_key) = ed25519::keypair(&key); 30 | let secret_key = secret_key.to_vec(); 31 | let public_key = public_key.to_vec(); 32 | Wallet { 33 | secret_key, 34 | public_key, 35 | } 36 | } 37 | 38 | /// GetAddress returns wallet address 39 | pub fn get_address(&self) -> String { 40 | let mut pub_hash: Vec = self.public_key.clone(); 41 | hash_pub_key(&mut pub_hash); 42 | let address = Address { 43 | body: pub_hash, 44 | scheme: Scheme::Base58, 45 | hash_type: HashType::Script, 46 | ..Default::default() 47 | }; 48 | address.encode().unwrap() 49 | } 50 | } 51 | 52 | /// HashPubKey hashes public key 53 | pub fn hash_pub_key(pubKey: &mut Vec) { 54 | let mut hasher1 = Sha256::new(); 55 | hasher1.input(pubKey); 56 | hasher1.result(pubKey); 57 | let mut hasher2 = Ripemd160::new(); 58 | hasher2.input(pubKey); 59 | pubKey.resize(20, 0); 60 | hasher2.result(pubKey); 61 | } 62 | 63 | pub struct Wallets { 64 | wallets: HashMap, 65 | } 66 | 67 | impl Wallets { 68 | /// NewWallets creates Wallets and fills it from a file if it exists 69 | pub fn new() -> Result { 70 | let mut wlt = Wallets { 71 | wallets: HashMap::::new(), 72 | }; 73 | let db = sled::open("data/wallets")?; 74 | 75 | for item in db.into_iter() { 76 | let i = item?; 77 | let address = String::from_utf8(i.0.to_vec())?; 78 | let wallet = deserialize(&i.1.to_vec())?; 79 | wlt.wallets.insert(address, wallet); 80 | } 81 | drop(db); 82 | Ok(wlt) 83 | } 84 | 85 | /// CreateWallet adds a Wallet to Wallets 86 | pub fn create_wallet(&mut self) -> String { 87 | let wallet = Wallet::new(); 88 | let address = wallet.get_address(); 89 | self.wallets.insert(address.clone(), wallet); 90 | info!("create wallet: {}", address); 91 | address 92 | } 93 | 94 | /// GetAddresses returns an array of addresses stored in the wallet file 95 | pub fn get_all_addresses(&self) -> Vec { 96 | let mut addresses = Vec::::new(); 97 | for (address, _) in &self.wallets { 98 | addresses.push(address.clone()); 99 | } 100 | addresses 101 | } 102 | 103 | /// GetWallet returns a Wallet by its address 104 | pub fn get_wallet(&self, address: &str) -> Option<&Wallet> { 105 | self.wallets.get(address) 106 | } 107 | 108 | /// SaveToFile saves wallets to a file 109 | pub fn save_all(&self) -> Result<()> { 110 | let db = sled::open("data/wallets")?; 111 | 112 | for (address, wallet) in &self.wallets { 113 | let data = serialize(wallet)?; 114 | db.insert(address, data)?; 115 | } 116 | 117 | db.flush()?; 118 | drop(db); 119 | Ok(()) 120 | } 121 | } 122 | 123 | #[cfg(test)] 124 | mod test { 125 | use super::*; 126 | 127 | #[test] 128 | fn test_create_wallet_and_hash() { 129 | let w1 = Wallet::new(); 130 | let w2 = Wallet::new(); 131 | assert_ne!(w1, w2); 132 | assert_ne!(w1.get_address(), w2.get_address()); 133 | 134 | let mut p2 = w2.public_key.clone(); 135 | hash_pub_key(&mut p2); 136 | assert_eq!(p2.len(), 20); 137 | let pub_key_hash = Address::decode(&w2.get_address()).unwrap().body; 138 | assert_eq!(pub_key_hash, p2); 139 | } 140 | 141 | #[test] 142 | fn test_wallets() { 143 | let mut ws = Wallets::new().unwrap(); 144 | let wa1 = ws.create_wallet(); 145 | let w1 = ws.get_wallet(&wa1).unwrap().clone(); 146 | ws.save_all().unwrap(); 147 | 148 | let ws2 = Wallets::new().unwrap(); 149 | let w2 = ws2.get_wallet(&wa1).unwrap(); 150 | assert_eq!(&w1, w2); 151 | } 152 | 153 | #[test] 154 | #[should_panic] 155 | fn test_wallets_not_exist() { 156 | let w3 = Wallet::new(); 157 | let ws2 = Wallets::new().unwrap(); 158 | ws2.get_wallet(&w3.get_address()).unwrap(); 159 | } 160 | 161 | #[test] 162 | fn test_signature() { 163 | let w = Wallet::new(); 164 | let signature = ed25519::signature("test".as_bytes(), &w.secret_key); 165 | assert!(ed25519::verify( 166 | "test".as_bytes(), 167 | &w.public_key, 168 | &signature 169 | )); 170 | } 171 | } 172 | --------------------------------------------------------------------------------