Skip to content

Instantly share code, notes, and snippets.

@dandax123
Created May 11, 2023 05:43
Show Gist options
  • Save dandax123/ca4b0014aa720503602ebdde04e75167 to your computer and use it in GitHub Desktop.
Save dandax123/ca4b0014aa720503602ebdde04e75167 to your computer and use it in GitHub Desktop.
Simple Chain
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