redgold_schema/
pow.rs

1use crate::proto_serde::ProtoSerde;
2use crate::structs::{Hash, PoWProof, PoWProofType, Transaction};
3use crate::{bytes_data, RgResult, SafeOption};
4use sha3::Digest;
5use std::time::Instant;
6
7
8fn check_difficulty_bytes(vec: &Vec<u8>, leading_zeros_bytes: usize) -> bool {
9    vec.len() >= leading_zeros_bytes &&
10    vec.iter().take(leading_zeros_bytes).all(|&b| b == 0)
11}
12
13fn check_difficulty_bits(vec: &Vec<u8>, leading_zero_bits: usize) -> bool {
14    let mut count = 0;
15    for &byte in vec.iter() {
16        if byte == 0 {
17            // If the byte is 0, all its bits are zero.
18            count += 8; // 8 bits in a byte
19        } else {
20            // If the byte is not 0, count the leading zeros and break.
21            count += byte.leading_zeros() as usize; // Count leading zeros in this byte
22            break;
23        }
24    }
25    count > leading_zero_bits
26}
27
28
29
30impl PoWProof {
31    pub fn from_hash_sha3_256(hash: &Hash, difficulty: usize) -> RgResult<PoWProof> {
32        let mut proof = PoWProof::default();
33        proof.proof_type = PoWProofType::Sha3256Nonce as i32;
34        let mut nonce: i64 = 0;
35        loop {
36            proof.index_counter = bytes_data(nonce.to_be_bytes().to_vec());
37            if proof.verify(hash, difficulty)? {
38                break
39            }
40            nonce += 1;
41        }
42        // While true, increment the nonce and check if the hash meets the difficulty target
43
44        Ok(proof)
45    }
46
47    pub fn merged_bytes(&self, hash: &Hash) -> RgResult<Vec<u8>> {
48        let hash_bytes = hash.proto_serialize();
49        let nonce = self.index_counter.safe_get()?.value.clone();
50        let mut merged = hash_bytes.clone();
51        merged.extend_from_slice(&*nonce);
52        Ok(merged)
53    }
54
55    pub fn merged_digest_hash(&self, hash: &Hash) -> RgResult<Hash> {
56        let merged = self.merged_bytes(hash)?;
57        Ok(Hash::digest(merged))
58    }
59
60    pub fn verify(&self, hash: &Hash, difficulty: usize) -> RgResult<bool> {
61        Ok(check_difficulty_bytes(&self.merged_digest_hash(&hash)?.raw_bytes()?, difficulty))
62    }
63
64    pub fn merged_hex(&self, hash: &Hash) -> RgResult<String> {
65        Ok(hex::encode(self.merged_digest_hash(hash)?.raw_bytes()?))
66    }
67
68    pub fn nonce_int(&self) -> RgResult<i64> {
69        Ok(i64::from_be_bytes(self.index_counter.safe_get()?.value.clone().as_slice().try_into().expect("nonce")))
70    }
71}
72
73
74#[test]
75fn test_pow() {
76    // This means we want 1 u8 leading zeroes
77    let difficulty = 1;
78
79    let mut elapsed_all = vec![];
80
81    for i in 0..30 {
82        let now = Instant::now();
83        let string = format!("hello{}", i);
84        let hash = Hash::from_string_calculate(&*string);
85        let proof = PoWProof::from_hash_sha3_256(&hash, difficulty).expect("proof");
86        proof.verify(&hash, difficulty).expect("verify");
87        println!("hash: {:?}", hash.hex());
88        println!("merged hex bytes: {:?}", hex::encode(proof.merged_bytes(&hash).expect("")));
89        println!("Proof merged hash: {:?}", proof.merged_hex(&hash).expect("merged_hex"));
90        println!("Proof merged bytes: {:?}", proof.merged_digest_hash(&hash).expect("merged_hex").vec());
91        println!("Proof nonce: {:?}", proof.nonce_int().expect("nonce_int"));
92        let elapsed = now.elapsed();
93        elapsed_all.push(elapsed.as_millis());
94        println!("Elapsed: {:?}", elapsed);
95    }
96    let avg = elapsed_all.iter().sum::<u128>() / elapsed_all.len() as u128;
97    println!("Average: {:?}", avg);
98
99}
100
101pub trait TransactionPowValidate {
102    fn pow_validate(&self) -> RgResult<bool>;
103}
104
105impl TransactionPowValidate for Transaction {
106    fn pow_validate(&self) -> RgResult<bool> {
107        let options = self.options.safe_get_msg("Missing tx options in pow validate")?;
108        let proof = options
109            .pow_proof.safe_get_msg("Missing pow proof")?;
110        proof.verify(&self.signable_hash(), 1)
111    }
112}