tofuri_stake/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3use serde_big_array::BigArray;
4use sha2::Digest;
5use sha2::Sha256;
6use std::error::Error;
7use tofuri_core::*;
8use tofuri_key::Key;
9pub trait Stake {
10    fn get_timestamp(&self) -> u32;
11    fn get_deposit(&self) -> bool;
12    fn get_fee_bytes(&self) -> AmountBytes;
13    fn hash(&self) -> Hash;
14    fn hash_input(&self) -> [u8; 9];
15}
16impl Stake for StakeA {
17    fn get_timestamp(&self) -> u32 {
18        self.timestamp
19    }
20    fn get_deposit(&self) -> bool {
21        self.deposit
22    }
23    fn get_fee_bytes(&self) -> AmountBytes {
24        tofuri_int::to_be_bytes(self.fee)
25    }
26    fn hash(&self) -> Hash {
27        hash(self)
28    }
29    fn hash_input(&self) -> [u8; 9] {
30        hash_input(self)
31    }
32}
33impl Stake for StakeB {
34    fn get_timestamp(&self) -> u32 {
35        self.timestamp
36    }
37    fn get_deposit(&self) -> bool {
38        self.deposit
39    }
40    fn get_fee_bytes(&self) -> AmountBytes {
41        self.fee
42    }
43    fn hash(&self) -> Hash {
44        hash(self)
45    }
46    fn hash_input(&self) -> [u8; 9] {
47        hash_input(self)
48    }
49}
50#[derive(Serialize, Deserialize, Clone, Debug)]
51pub struct StakeA {
52    pub amount: u128,
53    pub fee: u128,
54    pub deposit: bool,
55    pub timestamp: u32,
56    #[serde(with = "BigArray")]
57    pub signature: SignatureBytes,
58    pub input_address: AddressBytes,
59    pub hash: Hash,
60}
61#[derive(Serialize, Deserialize, Debug, Clone)]
62pub struct StakeB {
63    pub amount: AmountBytes,
64    pub fee: AmountBytes,
65    pub deposit: bool,
66    pub timestamp: u32,
67    #[serde(with = "BigArray")]
68    pub signature: SignatureBytes,
69}
70impl StakeA {
71    pub fn b(&self) -> StakeB {
72        StakeB {
73            amount: tofuri_int::to_be_bytes(self.amount),
74            fee: tofuri_int::to_be_bytes(self.fee),
75            deposit: self.deposit,
76            timestamp: self.timestamp,
77            signature: self.signature,
78        }
79    }
80    pub fn hash(&self) -> Hash {
81        hash(self)
82    }
83    pub fn sign(deposit: bool, amount: u128, fee: u128, timestamp: u32, key: &Key) -> Result<StakeA, Box<dyn Error>> {
84        let mut stake_a = StakeA {
85            amount: tofuri_int::floor(amount),
86            fee: tofuri_int::floor(fee),
87            deposit,
88            timestamp,
89            signature: [0; 64],
90            input_address: [0; 20],
91            hash: [0; 32],
92        };
93        stake_a.hash = stake_a.hash();
94        stake_a.signature = key.sign(&stake_a.hash)?;
95        stake_a.input_address = key.address_bytes();
96        Ok(stake_a)
97    }
98}
99impl StakeB {
100    pub fn a(&self, input_address: Option<AddressBytes>) -> Result<StakeA, Box<dyn Error>> {
101        let input_address = input_address.unwrap_or(self.input_address()?);
102        Ok(StakeA {
103            amount: tofuri_int::from_be_slice(&self.amount),
104            fee: tofuri_int::from_be_slice(&self.fee),
105            deposit: self.deposit,
106            timestamp: self.timestamp,
107            signature: self.signature,
108            input_address,
109            hash: self.hash(),
110        })
111    }
112    pub fn hash(&self) -> Hash {
113        hash(self)
114    }
115    fn input_address(&self) -> Result<AddressBytes, Box<dyn Error>> {
116        Ok(Key::address(&self.input_public_key()?))
117    }
118    fn input_public_key(&self) -> Result<PublicKeyBytes, Box<dyn Error>> {
119        Key::recover(&self.hash(), &self.signature)
120    }
121}
122fn hash<T: Stake>(stake: &T) -> Hash {
123    let mut hasher = Sha256::new();
124    hasher.update(stake.hash_input());
125    hasher.finalize().into()
126}
127fn hash_input<T: Stake>(stake: &T) -> [u8; 9] {
128    let mut bytes = [0; 9];
129    bytes[0..4].copy_from_slice(&stake.get_timestamp().to_be_bytes());
130    bytes[4..8].copy_from_slice(&stake.get_fee_bytes());
131    bytes[8] = if stake.get_deposit() { 1 } else { 0 };
132    bytes
133}
134impl Default for StakeA {
135    fn default() -> Self {
136        StakeA {
137            amount: 0,
138            fee: 0,
139            deposit: false,
140            timestamp: 0,
141            signature: [0; 64],
142            input_address: [0; 20],
143            hash: [0; 32],
144        }
145    }
146}
147impl Default for StakeB {
148    fn default() -> Self {
149        StakeB {
150            amount: [0; AMOUNT_BYTES],
151            fee: [0; AMOUNT_BYTES],
152            deposit: false,
153            timestamp: 0,
154            signature: [0; 64],
155        }
156    }
157}
158#[cfg(test)]
159mod tests {
160    use super::*;
161    #[test]
162    fn test_hash() {
163        assert_eq!(
164            StakeB::default().hash(),
165            [
166                62, 112, 119, 253, 47, 102, 214, 137, 224, 206, 230, 167, 207, 91, 55, 191, 45, 202, 124, 151, 154, 243, 86, 208, 163, 28, 188, 92, 133, 96,
167                92, 125
168            ]
169        );
170    }
171}