diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2025-10-21 20:41:50 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2025-10-21 21:14:12 +0800 |
| commit | ec257dc4496f4dd9f7b6a5a6cea033ee81206673 (patch) | |
| tree | 3fa4a04e9a03d12f088509a057ba4e3d2cab28a5 | |
| parent | 0ca3804ac22491ce00ef5391abef40a8444ff814 (diff) | |
refactor(blocks): use sha256
| -rw-r--r-- | Cargo.lock | 105 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/blocks.rs | 103 | ||||
| -rw-r--r-- | src/client.rs | 3 | ||||
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/network.rs | 18 | ||||
| -rw-r--r-- | src/transaction.rs | 3 |
7 files changed, 177 insertions, 59 deletions
@@ -3,13 +3,35 @@ version = 4 [[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] name = "bitcoin" version = "0.1.0" dependencies = [ + "bincode", "futures", "rand", "serde", "serde_json", + "sha2", "tokio", "tokio-serde", "tokio-util", @@ -22,6 +44,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[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 = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -34,6 +65,35 @@ 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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +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 = "educe" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -155,6 +215,16 @@ dependencies = [ ] [[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] name = "getrandom" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -386,6 +456,17 @@ dependencies = [ ] [[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 = "signal-hook-registry" version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -484,12 +565,36 @@ dependencies = [ ] [[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.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -11,3 +11,5 @@ tokio-serde = { version = "0.9.0", features = ["json"] } tokio-util = { version = "0.7.16", features = ["codec"] } futures = "0.3.31" rand = "0.9.2" +sha2 = "0.10.9" +bincode = "2.0.1" diff --git a/src/blocks.rs b/src/blocks.rs index 1fa8486..17e6d4f 100644 --- a/src/blocks.rs +++ b/src/blocks.rs @@ -1,5 +1,7 @@ +use bincode::Encode; +use sha2::{Digest, Sha256, digest::DynDigest}; use std::{ - hash::{DefaultHasher, Hash, Hasher}, + hash::{Hash, Hasher}, ops::Deref, }; @@ -7,68 +9,69 @@ use serde::{Deserialize, Serialize}; use crate::{ZERO_PREFIX_AMOUNT, transaction::Transaction}; -#[derive(Deserialize, Serialize, Clone, Copy, PartialEq)] +pub trait CryptoDigest { + fn digest(&self, state: &mut impl DynDigest); +} + +#[derive(Deserialize, Serialize, Clone, PartialEq, Encode)] pub struct Block { - pub prev_hash: u64, + pub prev_hash: Vec<u8>, pub trans: Transaction, - pub pow: Option<u64>, + pub pow: Vec<u8>, } impl Block { - fn new(prev_hash: Option<u64>, trans: Transaction) -> Self { + fn new(prev_hash: Option<&[u8]>, trans: Transaction) -> Self { Self { - prev_hash: prev_hash.unwrap_or(0), // special blocks + prev_hash: prev_hash + .unwrap_or(&[]) + .to_vec(), // special blocks trans, - pow: None, + pow: Vec::default(), } } - fn calc_pow(&self) -> u64 { + fn pref_zeros(hashed: &[u8]) -> Result<usize, usize> { + hashed + .iter() + .try_fold(0, |nonce, x| { + if nonce >= ZERO_PREFIX_AMOUNT { + Ok(nonce) + } else if *x == 0 { + Ok(nonce + 1) + } else { + Err(nonce) + } + }) + } + + fn calc_pow(&self) -> Vec<u8> { for i in 0.. { // reset every loop - let mut hasher = DefaultHasher::new(); - (&self.prev_hash, &self.trans, i).hash(&mut hasher); - let hashed = hasher.finish(); - if hashed - .to_string() - .starts_with( - &"0".repeat(ZERO_PREFIX_AMOUNT) - .to_string(), - ) - { - return hashed; + let mut hasher = Sha256::new(); + Digest::update(&mut hasher, bincode::encode_to_vec((&self.prev_hash, &self.trans, i), bincode::config::standard()).unwrap()); + let hashed = hasher.finalize(); + if Self::pref_zeros(&hashed).is_ok() { + return hashed.to_vec(); } } unreachable!() } pub fn verify_pow(&mut self) -> bool { - let mut hasher = DefaultHasher::new(); - self.hash(&mut hasher); - hasher - .finish() - .to_string() - .to_string() - .starts_with( - &"0".repeat(ZERO_PREFIX_AMOUNT) - .to_string(), - ) + let mut hasher = Sha256::new(); + Digest::update(&mut hasher, bincode::encode_to_vec(&*self, bincode::config::standard()).unwrap()); + Self::pref_zeros(&hasher.finalize()).is_ok() } pub fn calc_set_pow(&mut self) { - self.pow = Some(self.calc_pow()); + self.pow = self.calc_pow(); } } -impl Hash for Block { - fn hash<H: Hasher>(&self, state: &mut H) { - self.prev_hash - .hash(state); - self.trans - .hash(state); - self.pow - .expect("Cannot hash whole block with no PoW") - .hash(state); +impl CryptoDigest for Block { + fn digest(&self, state: &mut impl DynDigest) { + state.update(&bincode::encode_to_vec((&self.prev_hash, &self.trans, &self.pow), bincode::config::standard()).unwrap()); } } @@ -85,16 +88,17 @@ impl BlockChain { } pub fn new_block(&self, trans: Transaction) -> Block { - let mut hasher = DefaultHasher::new(); - Block::new( - self.blocks - .last() - .map(|b| { - b.hash(&mut hasher); - hasher.finish() - }), - trans, - ) + let mut hasher = Sha256::new(); + let prev = self + .blocks + .last(); + let prev_hash = if let Some(b) = prev { + b.digest(&mut hasher); + Some(&*hasher.finalize()) + } else { + None + }; + Block::new(prev_hash, trans) } pub fn store(&mut self, block: Block) { @@ -106,6 +110,7 @@ impl BlockChain { impl Deref for BlockChain { type Target = Vec<Block>; + fn deref(&self) -> &Self::Target { &self.blocks } diff --git a/src/client.rs b/src/client.rs index 457a70d..eb417fd 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,7 +1,8 @@ +use bincode::Encode; use rand::Rng; use serde::{Deserialize, Serialize}; -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq)] +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Encode)] pub struct Client { id: u32, } @@ -6,4 +6,4 @@ pub mod client; pub mod network; -const ZERO_PREFIX_AMOUNT: usize = 5; // TODO: make this dynamic +const ZERO_PREFIX_AMOUNT: usize = 2; // TODO: make this dynamic diff --git a/src/network.rs b/src/network.rs index 753f743..c18ae07 100644 --- a/src/network.rs +++ b/src/network.rs @@ -75,7 +75,7 @@ impl Network { let peer = Arc::new(Mutex::new(Peer::new( self.this .clone(), - TcpStream::connect("192.168.143.90:6767") + TcpStream::connect("192.168.1.16:6767") .await .unwrap(), ))); @@ -222,8 +222,11 @@ impl Peer { async fn handle(parent: Weak<Mutex<Network>>, req: Request) { match req { - Request::Block(mut block) => match block.pow { - Some(_pow) => { + Request::Block(mut block) => { + if !block + .pow + .is_empty() + { if !block.verify_pow() { eprintln!("Rejecting remote block, POW verification failed"); // TODO: log remote IP return; @@ -237,8 +240,8 @@ impl Peer { .lock() .await .store(block) - } - None => { + } else { + print!("as"); block.calc_set_pow(); let parent = parent .upgrade() @@ -250,7 +253,7 @@ impl Peer { .broadcast(Request::Block(block)) .await; } - }, + } Request::Ibd(bc) => match bc { Some(bc) => { let parent = parent @@ -267,10 +270,11 @@ impl Peer { || (self_bc .blocks .iter() + // TODO: Optimize via try_fold .fold(true, |i, b| { if i { b.pow - .is_none() + .is_empty() } else { false } diff --git a/src/transaction.rs b/src/transaction.rs index dcaff49..760f080 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,8 +1,9 @@ +use bincode::Encode; use serde::{Deserialize, Serialize}; use crate::client::Client; -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq)] +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Encode)] pub struct Transaction { from: Client, to: Client, |
