cryptonote_raw_crypto/
difficulty.rs

1extern "C" {
2  fn next_difficulty(
3    timestamps: *mut u64,
4    timestamps_length: u16,
5    cumulative_difficulties: *const u64,
6    difficulties_length: u16,
7    difficulty_config: *const u64,
8  ) -> u64;
9}
10
11#[repr(C)]
12pub struct Difficulty {
13  pub target: u8,  // seconds
14  pub cut: u8,     //  timestamps to cut after sorting
15  pub lag: u16,    //
16  pub window: u32, // expected numbers of blocks per day
17}
18
19impl From<&Difficulty> for u64 {
20  fn from(data: &Difficulty) -> u64 {
21    let mut ret: u64;
22    ret = (data.window as u64) << 32;
23    ret += (data.lag as u64) << 16;
24    ret += (data.cut as u64) << 8;
25    ret += data.target as u64;
26    ret
27  }
28}
29
30impl From<&u64> for Difficulty {
31  fn from(data: &u64) -> Difficulty {
32    let target = (data & 0xFF) as u8;
33    let cut = (data >> 8) as u8 & 0xFF as u8;
34    let lag = (data >> 16) as u16 & 0xFFFF as u16;
35    let window = (data >> 32) as u32;
36    Difficulty {
37      target,
38      cut,
39      lag,
40      window
41    }
42  }
43}
44
45impl Difficulty {
46  pub fn next(&self, timestamps: &mut [u64], cumulative_difficulties: &[u64]) -> u64 {
47    unsafe {
48      let value = u64::from(self);
49      return next_difficulty(
50        timestamps.as_mut_ptr(),
51        timestamps.len() as u16,
52        cumulative_difficulties.as_ptr(),
53        cumulative_difficulties.len() as u16,
54        &value as *const u64,
55      );
56    }
57  }
58}
59
60#[cfg(test)]
61mod tests {
62  use super::*;
63  use std::cmp;
64  use std::fs::{canonicalize, File};
65  use std::io::{prelude::*, BufReader};
66  use std::path::PathBuf;
67
68  #[test]
69  fn should_test_difficulty() {
70    let diff = Difficulty {
71      target: 120,
72      window: 720,
73      cut: 60,
74      lag: 15,
75    };
76    let diffu64 = u64::from(&diff);
77
78    let diff1 = Difficulty::from(&diffu64);
79
80    assert!(diff1.window == diff.window);
81    assert!(diff1.target == diff.target);
82    assert!(diff1.cut == diff.cut);
83    assert!(diff1.lag == diff.lag);
84
85    let path = PathBuf::from("./tests/difficulty.txt");
86    let str = canonicalize(path);
87    let f = File::open(str.unwrap()).unwrap();
88    let file = BufReader::new(&f);
89    let mut n: u64 = 0;
90    let mut timestamps: Vec<u64> = Vec::with_capacity(1);
91    let mut cumulative_difficulties: Vec<u64> = Vec::with_capacity(1);
92    let mut cumulative_difficulty: u64 = 0;
93    for (_num, line) in file.lines().enumerate() {
94      let l = line.unwrap();
95      let split: Vec<&str> = l.split_whitespace().collect();
96      let timestamp = split[0].parse::<u64>().unwrap();
97      let difficulty = split[1].parse::<u64>().unwrap();
98      let begin: usize;
99      let end: usize;
100      let window = diff.window.clone();
101      let lag = diff.lag.clone();
102      if n < (window + lag as u32) as u64 {
103        begin = 0;
104        end = cmp::min(n as usize, window as usize);
105      } else {
106        end = n as usize - lag as usize;
107        begin = end - window as usize;
108      }
109      let mut ts : Vec<u64> = vec![];
110      for i in begin..end {
111        ts.push(timestamps[i]);
112      }
113      let res: u64 = diff.next(
114        &mut ts[0..],
115        &cumulative_difficulties[begin..end],
116      );
117      assert!(res == difficulty);
118      timestamps.push(timestamp);
119      cumulative_difficulty += difficulty;
120      cumulative_difficulties.push(cumulative_difficulty);
121
122      n += 1;
123    }
124  }
125}