1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::crypto::{hash, SaitoHash, SaitoPublicKey};
use bigint::uint::U256;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
extern crate hex;

#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GoldenTicket {
    target: SaitoHash,
    random: SaitoHash,
    #[serde_as(as = "[_; 33]")]
    publickey: SaitoPublicKey,
}

impl GoldenTicket {
    #[allow(clippy::new_without_default)]
    pub fn new(target: SaitoHash, random: SaitoHash, publickey: SaitoPublicKey) -> Self {
        return Self {
            target,
            random,
            publickey,
        };
    }

    // TODO - review exact solution generated and mechanism to determine validity
    pub fn generate_solution(
        previous_block_hash: SaitoHash,
        random_bytes: SaitoHash,
        publickey: SaitoPublicKey,
    ) -> SaitoHash {
        let mut vbytes: Vec<u8> = vec![];
        vbytes.extend(&previous_block_hash);
        vbytes.extend(&random_bytes);
        vbytes.extend(&publickey);
        hash(&vbytes)
    }

    // TODO - review exact algorithm in use here
    pub fn is_valid_solution(solution: SaitoHash, difficulty: u64) -> bool {
        let leading_zeroes_required: u64 = difficulty / 16;
        let final_digit: u8 = 15 - ((difficulty % 16) as u8);

        let mut target_string = String::from("");

        //
        // decidely ungainly
        //
        for i in 0..64 {
            if (i as u64) < leading_zeroes_required {
                target_string.push('0');
            } else {
                if (i as u64) == leading_zeroes_required {
                    if final_digit == 0 {
                        target_string.push('0');
                    }
                    if final_digit == 1 {
                        target_string.push('1');
                    }
                    if final_digit == 2 {
                        target_string.push('2');
                    }
                    if final_digit == 3 {
                        target_string.push('3');
                    }
                    if final_digit == 4 {
                        target_string.push('4');
                    }
                    if final_digit == 5 {
                        target_string.push('5');
                    }
                    if final_digit == 6 {
                        target_string.push('6');
                    }
                    if final_digit == 7 {
                        target_string.push('7');
                    }
                    if final_digit == 8 {
                        target_string.push('8');
                    }
                    if final_digit == 9 {
                        target_string.push('9');
                    }
                    if final_digit == 10 {
                        target_string.push('A');
                    }
                    if final_digit == 11 {
                        target_string.push('B');
                    }
                    if final_digit == 12 {
                        target_string.push('C');
                    }
                    if final_digit == 13 {
                        target_string.push('D');
                    }
                    if final_digit == 14 {
                        target_string.push('E');
                    }
                    if final_digit == 15 {
                        target_string.push('F');
                    }
                } else {
                    target_string.push('F');
                }
            }
        }

        let target_hash = hex::decode(target_string).expect("error generating target bytes array");

        let sol = U256::from_big_endian(&solution);
        let tgt = U256::from_big_endian(&target_hash);

        if sol <= tgt {
            return true;
        }

        return false;
    }

    pub fn get_target(&self) -> SaitoHash {
        self.target
    }

    pub fn get_random(&self) -> SaitoHash {
        self.random
    }

    pub fn get_publickey(&self) -> SaitoPublicKey {
        self.publickey
    }

    pub fn serialize_for_transaction(&self) -> Vec<u8> {
        let mut vbytes: Vec<u8> = vec![];
        vbytes.extend(&self.target);
        vbytes.extend(&self.random);
        vbytes.extend(&self.publickey);
        vbytes
    }

    pub fn deserialize_for_transaction(bytes: Vec<u8>) -> GoldenTicket {
        let target: SaitoHash = bytes[0..32].try_into().unwrap();
        let random: SaitoHash = bytes[32..64].try_into().unwrap();
        let publickey: SaitoPublicKey = bytes[64..97].try_into().unwrap();
        GoldenTicket::new(target, random, publickey)
    }
}