Created
May 11, 2023 05:43
-
-
Save dandax123/ca4b0014aa720503602ebdde04e75167 to your computer and use it in GitHub Desktop.
Simple Chain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fmt::{self, Debug, Display}; | |
use sha2::{Digest, Sha256}; | |
use std::rc::Rc; | |
const NUM_OF_ZEROS: usize = 3; | |
pub struct Block<T: std::fmt::Display> { | |
pub prev_block_hash: String, | |
nonce: u32, | |
data: MerkleTree<T>, | |
pub hash: String, | |
} | |
impl<T> Block<T> | |
where | |
T: Display + Default, | |
{ | |
pub fn new(mut data: MerkleTree<T>) -> Self { | |
data.build_tree(); | |
Self { | |
prev_block_hash: "".to_string(), | |
nonce: 0, | |
data, | |
hash: "".to_string(), | |
} | |
} | |
pub fn mine_block(&mut self) { | |
let (nonce, hash) = self.mine_new_block(NUM_OF_ZEROS); | |
self.nonce = nonce; | |
self.hash = hash; | |
} | |
pub fn mine_new_block(&mut self, num_of_zeros: usize) -> (u32, String) { | |
let mut nonce = 0; | |
let mut is_restriction_passed = false; | |
let mut hash = String::new(); | |
while !is_restriction_passed { | |
hash = self.hash_block(); | |
is_restriction_passed = Block::<T>::check_restriction(hash.as_str(), num_of_zeros); | |
nonce += 1; | |
self.nonce = nonce; | |
} | |
(nonce, hash) | |
} | |
fn check_restriction(hash: &str, num_of_zeros: usize) -> bool { | |
let z = "0".to_string(); | |
hash[..num_of_zeros] == z.repeat(num_of_zeros) | |
} | |
pub fn hash_block(&self) -> String { | |
let mut hasher = Sha256::new(); | |
hasher.update(self.get_string_rep().as_bytes()); | |
let hash_values: String = format!("{:X}", hasher.finalize()); | |
hash_values | |
} | |
pub fn get_string_rep(&self) -> String { | |
let a = &self.data.root.as_ref().unwrap().hash; | |
format!("{}-{}-{}", self.nonce, a, self.prev_block_hash) | |
} | |
} | |
impl<T> Display for Block<T> | |
where | |
T: Display, | |
{ | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
writeln!(f, "Block Hash: {}", self.hash) | |
} | |
} | |
#[derive(Default)] | |
pub struct Chain<T: Display> { | |
pub blocks: Vec<Block<T>>, | |
} | |
impl<T> Chain<T> | |
where | |
T: Display + Default, | |
{ | |
pub fn new() -> Self { | |
let mut root_block = Block::new(MerkleTree::new([ | |
T::default(), | |
T::default(), | |
T::default(), | |
T::default(), | |
])); | |
root_block.mine_block(); | |
Self { | |
blocks: vec![root_block], | |
} | |
} | |
pub fn add_new_block(&mut self, mut new_block: Block<T>) { | |
let y = self.blocks.as_slice(); | |
let b: &Block<T> = &y[y.len() - 1]; | |
let prev_hash = &b.hash; | |
new_block.prev_block_hash = prev_hash.to_string(); | |
new_block.mine_block(); | |
self.blocks.push(new_block); | |
} | |
pub fn view_chain(&self) { | |
self.blocks | |
.iter() | |
.enumerate() | |
.for_each(|b| println!("Block: {} {}", b.0, b.1)); | |
} | |
} | |
const MAX_DATA_LIMIT: usize = 4; | |
#[derive(Clone, Debug, Default)] | |
pub struct MerkleTree<T: Display> { | |
pub root: Option<Rc<MerkleTreeNode<T>>>, | |
children: [Rc<MerkleTreeNode<T>>; MAX_DATA_LIMIT], | |
} | |
impl<T> fmt::Display for MerkleTree<T> | |
where | |
T: Display + Default, | |
{ | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
std::fmt::Display::fmt(&self.root.as_ref().unwrap(), f) | |
} | |
} | |
impl<T> MerkleTree<T> | |
where | |
T: Display + Default, | |
{ | |
pub fn new(values: [T; MAX_DATA_LIMIT]) -> Self { | |
let children = values.map(MerkleTreeNode::new_leaf); | |
Self { | |
root: None, | |
children, | |
} | |
} | |
pub fn build_tree(&mut self) { | |
let g = MerkleTree::<T>::build_tree_rec(&self.children); | |
self.root = g; | |
} | |
pub fn build_tree_rec(values: &[Rc<MerkleTreeNode<T>>]) -> Option<Rc<MerkleTreeNode<T>>> { | |
let half = values.len() / 2; | |
if values.len() == 2 || values.len() == 1 { | |
let a = values[0].clone(); | |
let b = { | |
if values.len() == 2 { | |
Some(values[1].clone()) | |
} else { | |
None | |
} | |
}; | |
let y = MerkleTreeNode { | |
hash: MerkleTreeNode::<T>::hash( | |
format!( | |
"{}{}", | |
a.hash, | |
b.as_ref().unwrap_or(&MerkleTreeNode::empty_leaf()).hash | |
) | |
.as_str(), | |
), | |
left: Some(a), | |
right: b, | |
value: T::default(), | |
}; | |
return Some(y.into()); | |
} | |
let left = MerkleTree::<T>::build_tree_rec(&values[..half]); | |
let right = MerkleTree::<T>::build_tree_rec(&values[half..]); | |
let hash = MerkleTreeNode::<T>::hash( | |
format!( | |
"{}{}", | |
left.as_ref().unwrap().hash, | |
right.as_ref().unwrap().hash | |
) | |
.as_str(), | |
); | |
Some(Rc::new(MerkleTreeNode { | |
value: T::default(), | |
left, | |
right, | |
hash, | |
})) | |
} | |
} | |
#[derive(Clone, Debug, Default)] | |
pub struct MerkleTreeNode<T> { | |
pub value: T, | |
pub hash: String, | |
pub left: Option<Rc<MerkleTreeNode<T>>>, | |
pub right: Option<Rc<MerkleTreeNode<T>>>, | |
} | |
impl<T> MerkleTreeNode<T> | |
where | |
T: Display + Default, | |
{ | |
pub fn new_leaf(value: T) -> Rc<MerkleTreeNode<T>> { | |
let y = MerkleTreeNode { | |
hash: MerkleTreeNode::<T>::hash(value.to_string().as_ref()), | |
value, | |
right: None, | |
left: None, | |
}; | |
Rc::new(y) | |
} | |
pub fn empty_leaf() -> Rc<MerkleTreeNode<T>> { | |
let y = MerkleTreeNode { | |
value: T::default(), | |
right: None, | |
left: None, | |
hash: MerkleTreeNode::<T>::hash(T::default().to_string().as_ref()), | |
}; | |
Rc::new(y) | |
} | |
pub fn hash(value: &str) -> String { | |
let mut hasher = Sha256::new(); | |
hasher.update(value.as_bytes()); | |
let hash_values: String = format!("{:X}", hasher.finalize()); | |
hash_values | |
} | |
} | |
impl<T> fmt::Display for MerkleTreeNode<T> | |
where | |
T: Default + Display, | |
{ | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
writeln!(f, "Root: {}", &self.hash)?; | |
if let Some(a) = &self.left { | |
std::fmt::Display::fmt(&a, f)?; | |
}; | |
if let Some(b) = &self.right { | |
std::fmt::Display::fmt(&b, f)?; | |
}; | |
Ok(()) | |
} | |
} | |
#[derive(Debug, Default)] | |
enum Gender { | |
#[default] | |
Male, | |
Female, | |
} | |
#[derive(Debug, Default)] | |
struct Student { | |
name: String, | |
age: u8, | |
gender: Gender, | |
student_no: u32, | |
} | |
impl Display for Gender { | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
match self { | |
&Gender::Female => write!(f, "Male"), | |
Gender::Male => write!(f, "Female"), | |
} | |
} | |
} | |
impl Display for Student { | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
writeln!( | |
f, | |
"{}-{}-{}-{}", | |
self.student_no, self.age, self.gender, self.name | |
)?; | |
Ok(()) | |
} | |
} | |
fn main() { | |
let student_merkletree_1 = MerkleTree::new([ | |
Student { | |
name: "121".to_string(), | |
age: 4, | |
gender: Gender::Male, | |
student_no: 10129012, | |
}, | |
Student { | |
name: "121".to_string(), | |
age: 4, | |
gender: Gender::Male, | |
student_no: 10129012, | |
}, | |
Student { | |
name: "121".to_string(), | |
age: 4, | |
gender: Gender::Male, | |
student_no: 10129012, | |
}, | |
Student { | |
name: "121".to_string(), | |
age: 4, | |
gender: Gender::Female, | |
student_no: 10129012, | |
}, | |
]); | |
let student_block_1 = Block::new(student_merkletree_1); | |
let mut my_chain: Chain<Student> = Chain::new(); | |
my_chain.add_new_block(student_block_1); | |
my_chain.view_chain(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment