Coverage Report

Created: 2022-11-10 19:56

/home/runner/work/creditcoin/creditcoin/pallets/difficulty/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
1
#![cfg_attr(not(feature = "std"), no_std)]#![cfg_attr(not(feature = "std"), no_std)]
2
3
use frame_support::{pallet_prelude::*, sp_runtime, traits::OnTimestampSet};
4
pub use pallet::*;
5
use primitives::Difficulty;
6
use sp_arithmetic::traits::BaseArithmetic;
7
use sp_runtime::traits::{SaturatedConversion, UniqueSaturatedInto};
8
9
#[cfg(test)]
10
mod mock;
11
12
#[allow(clippy::unnecessary_cast)]
13
pub mod weights;
14
15
#[cfg(test)]
16
mod tests;
17
18
mod benchmarking;
19
20
7
#[derive(
Clone3
, Encode,
D2
ecod
e2
, Eq,
P0
artialE
q0
,
RuntimeDebug0
,
TypeInfo0
,
MaxEncodedLen0
)]
21
0
pub struct DifficultyAndTimestamp<Moment> {
22
  difficulty: Difficulty,
23
  timestamp: Moment,
24
}
25
26
0
#[frame_support::pallet]
27
0
pub mod pallet {
28
0
  use frame_support::{
29
0
    pallet_prelude::*,
30
0
    sp_runtime::traits::{MaybeSerializeDeserialize, SaturatedConversion},
31
0
  };
32
0
  use frame_system::pallet_prelude::*;
33
0
  use primitives::Difficulty;
34
0
  use sp_arithmetic::traits::{BaseArithmetic, UniqueSaturatedInto, Zero};
35
0
36
0
  use crate::DifficultyAndTimestamp;
37
0
38
0
  #[pallet::config]
39
0
  pub trait Config: frame_system::Config {
40
0
    type Moment: Parameter
41
0
      + Default
42
0
      + Copy
43
0
      + MaxEncodedLen
44
0
      + scale_info::StaticTypeInfo
45
0
      + SaturatedConversion
46
0
      + BaseArithmetic
47
0
      + UniqueSaturatedInto<i64>
48
0
      + MaybeSerializeDeserialize;
49
0
50
0
    type WeightInfo: WeightInfo;
51
0
  }
52
0
53
0
  pub trait WeightInfo {
54
0
    fn set_target_block_time() -> Weight;
55
0
    fn set_adjustment_period() -> Weight;
56
0
  }
57
0
58
0
  #[pallet::pallet]
59
0
  #[pallet::generate_store(pub(super) trait Store)]
60
0
  pub struct Pallet<T>(_);
61
0
62
0
  #[pallet::genesis_config]
63
0
  pub struct GenesisConfig<T: Config> {
64
0
    pub initial_difficulty: Difficulty,
65
0
    pub target_time: T::Moment,
66
0
    pub difficulty_adjustment_period: i64,
67
0
  }
68
0
69
0
  #[cfg(feature = "std")]
70
0
  impl<T: Config> Default for GenesisConfig<T> {
71
4
    fn default() -> Self {
72
4
      Self {
73
4
        initial_difficulty: Difficulty::from(1_000_000),
74
4
        target_time: T::Moment::default(),
75
4
        difficulty_adjustment_period: 28,
76
4
      }
77
4
    }
78
0
  }
79
0
80
12
  #[pallet::error]
81
0
  pub enum Error<T> {
82
0
    ZeroTargetTime,
83
0
    ZeroAdjustmentPeriod,
84
0
    NegativeAdjustmentPeriod,
85
0
  }
86
0
87
2
  #[pallet::genesis_build]
88
0
  impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
89
2
    fn build(&self) {
90
2
      CurrentDifficulty::<T>::put(self.initial_difficulty);
91
2
      TargetBlockTime::<T>::put(self.target_time);
92
2
      DifficultyAdjustmentPeriod::<T>::put(self.difficulty_adjustment_period);
93
2
    }
94
0
  }
95
0
96
13
  #[pallet::storage]
97
0
  #[pallet::getter(fn previous_difficulties_and_timestamps)]
98
0
  pub type PreviousDifficultiesAndTimestamps<T> = StorageValue<
99
0
    _,
100
0
    BoundedVec<DifficultyAndTimestamp<<T as Config>::Moment>, ConstU32<2>>,
101
0
    ValueQuery,
102
0
  >;
103
0
104
12
  #[pallet::storage]
105
0
  #[pallet::getter(fn difficulty)]
106
0
  pub type CurrentDifficulty<T> = StorageValue<_, Difficulty, ValueQuery>;
107
0
108
8
  #[pallet::storage]
109
0
  pub type TargetBlockTime<T: Config> = StorageValue<_, T::Moment, ValueQuery>;
110
0
111
8
  #[pallet::storage]
112
0
  pub type DifficultyAdjustmentPeriod<T: Config> = StorageValue<_, i64, ValueQuery>;
113
0
114
0
  #[pallet::call]
115
  impl<T: Config> Pallet<T> {
116
    #[pallet::weight(<T as Config>::WeightInfo::set_target_block_time())]
117
    pub fn set_target_block_time(
118
      origin: OriginFor<T>,
119
      target_time: T::Moment,
120
    ) -> DispatchResult {
121
4
      ensure_root(origin)
?2
;
122
123
2
      ensure!(!target_time.is_zero(), 
Error::<T>::ZeroTargetTime1
);
124
125
1
      TargetBlockTime::<T>::put(target_time);
126
1
127
1
      Ok(())
128
4
    }
129
    #[pallet::weight(<T as Config>::WeightInfo::set_adjustment_period())]
130
    pub fn set_adjustment_period(origin: OriginFor<T>, period: i64) -> DispatchResult {
131
5
      ensure_root(origin)
?2
;
132
133
3
      ensure!(period != 0, 
Error::<T>::ZeroAdjustmentPeriod1
);
134
2
      ensure!(period > 0, 
Error::<T>::NegativeAdjustmentPeriod1
);
135
136
1
      DifficultyAdjustmentPeriod::<T>::put(period);
137
1
138
1
      Ok(())
139
5
    }
140
  }
141
}
142
143
// Adapted from zawy12's Simple EMA difficulty algorithm, license follows:
144
/*
145
  MIT License
146
147
  Copyright (c) 2017 zawy12
148
149
  Permission is hereby granted, free of charge, to any person obtaining a copy
150
  of this software and associated documentation files (the "Software"), to deal
151
  in the Software without restriction, including without limitation the rights
152
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
153
  copies of the Software, and to permit persons to whom the Software is
154
  furnished to do so, subject to the following conditions:
155
156
  The above copyright notice and this permission notice shall be included in all
157
  copies or substantial portions of the Software.
158
159
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
160
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
162
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
163
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
164
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
165
  SOFTWARE.
166
*/
167
4
fn next_difficulty<M>(
168
4
  previous: &[DifficultyAndTimestamp<M>],
169
4
  target_time: M,
170
4
  initial_difficulty: Difficulty,
171
4
  adjustment_period: i64,
172
4
) -> Difficulty
173
4
where
174
4
  M: SaturatedConversion
175
4
    + Copy
176
4
    + BaseArithmetic
177
4
    + UniqueSaturatedInto<i64>
178
4
    + frame_support::sp_std::fmt::Debug,
179
4
{
180
4
  let n = adjustment_period;
181
4
  log::debug!(
"previous {:?}"0
, previous);
182
4
  if previous.len() < 2 {
183
2
    return initial_difficulty;
184
2
  }
185
2
186
2
  let oldest = &previous[0];
187
2
  let newest = &previous[1];
188
2
189
2
  let t = target_time.saturated_into::<i64>() / 1000;
190
2
  log::debug!(
"t = {}"0
, t);
191
2
  let solve_time = (newest.timestamp.saturated_into::<i64>()
192
2
    - oldest.timestamp.saturated_into::<i64>())
193
2
    / 1000;
194
2
195
2
  log::debug!(
"solve time = {}"0
, solve_time);
196
2
  let solve_time = i64::max(-5 * t, i64::min(solve_time, 6 * t));
197
2
  log::debug!(
"ST = {}"0
, solve_time);
198
2
  let difficulty = newest.difficulty;
199
2
200
2
  let next_difficulty = (difficulty * n * t) / (n * t - t + solve_time);
201
2
202
2
  log::debug!(
"next difficulty = {}"0
, next_difficulty);
203
204
2
  next_difficulty
205
4
}
206
207
impl<T: Config> OnTimestampSet<T::Moment> for Pallet<T> {
208
2
  fn on_timestamp_set(current_timestamp: T::Moment) {
209
2
    let target_time = TargetBlockTime::<T>::get();
210
2
    let current_difficulty = Self::difficulty();
211
2
    let adjustment_period = DifficultyAdjustmentPeriod::<T>::get();
212
2
213
2
    let mut previous = PreviousDifficultiesAndTimestamps::<T>::get();
214
2
215
2
    let current =
216
2
      DifficultyAndTimestamp { difficulty: current_difficulty, timestamp: current_timestamp };
217
2
218
2
    if previous.len() < 2 {
219
1
      previous.try_push(current).expect("len < 2 checked above");
220
1
    } else {
221
1
      previous[0] = previous[1].clone();
222
1
      previous[1] = current;
223
1
    }
224
225
2
    let next_difficulty =
226
2
      next_difficulty(&previous, target_time, current_difficulty, adjustment_period);
227
2
    CurrentDifficulty::<T>::put(next_difficulty);
228
2
    PreviousDifficultiesAndTimestamps::<T>::put(previous);
229
2
  }
230
}