lib.rs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. use rstd::prelude::*;
  4. use codec::{Codec, Decode, Encode};
  5. use runtime_primitives::traits::{
  6. AccountIdConversion, MaybeSerialize, Member, One, SimpleArithmetic, Zero,
  7. };
  8. use runtime_primitives::ModuleId;
  9. use srml_support::traits::{Currency, ExistenceRequirement, Get, Imbalance, WithdrawReasons};
  10. use srml_support::{decl_module, decl_storage, ensure, Parameter};
  11. use rstd::collections::btree_map::BTreeMap;
  12. use system;
  13. mod errors;
  14. pub use errors::*;
  15. mod macroes;
  16. mod mock;
  17. mod tests;
  18. pub type BalanceOf<T> =
  19. <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
  20. pub type NegativeImbalance<T> =
  21. <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
  22. pub trait Trait: system::Trait + Sized {
  23. /// The currency that is managed by the module
  24. type Currency: Currency<Self::AccountId>;
  25. /// ModuleId for computing deterministic AccountId for the module
  26. type StakePoolId: Get<[u8; 8]>;
  27. /// Type that will handle various staking events
  28. type StakingEventsHandler: StakingEventsHandler<Self>;
  29. /// The type used as a stake identifier.
  30. type StakeId: Parameter
  31. + Member
  32. + SimpleArithmetic
  33. + Codec
  34. + Default
  35. + Copy
  36. + MaybeSerialize
  37. + PartialEq;
  38. /// The type used as slash identifier.
  39. type SlashId: Parameter
  40. + Member
  41. + SimpleArithmetic
  42. + Codec
  43. + Default
  44. + Copy
  45. + MaybeSerialize
  46. + PartialEq
  47. + Ord; //required to be a key in BTreeMap
  48. }
  49. pub trait StakingEventsHandler<T: Trait> {
  50. /// Handler for unstaking event.
  51. /// The handler is informed of the amount that was unstaked, and the value removed from stake is passed as a negative imbalance.
  52. /// The handler is responsible to consume part or all of the value (for example by moving it into an account). The remainder
  53. /// of the value that is not consumed should be returned as a negative imbalance.
  54. fn unstaked(
  55. id: &T::StakeId,
  56. unstaked_amount: BalanceOf<T>,
  57. remaining_imbalance: NegativeImbalance<T>,
  58. ) -> NegativeImbalance<T>;
  59. /// Handler for slashing event.
  60. /// NB: actually_slashed can be less than amount of the slash itself if the
  61. /// claim amount on the stake cannot cover it fully.
  62. /// The SlashId is optional, as slashing may not be associated with a slashing that was initiated, but was an immediate slashing.
  63. /// For Immediate slashes, the stake may have transitioned to NotStaked so handler should not assume the state
  64. /// is still in staked status.
  65. fn slashed(
  66. id: &T::StakeId,
  67. slash_id: Option<T::SlashId>,
  68. slashed_amount: BalanceOf<T>,
  69. remaining_stake: BalanceOf<T>,
  70. remaining_imbalance: NegativeImbalance<T>,
  71. ) -> NegativeImbalance<T>;
  72. }
  73. /// Default implementation just destroys the unstaked or slashed value
  74. impl<T: Trait> StakingEventsHandler<T> for () {
  75. fn unstaked(
  76. _id: &T::StakeId,
  77. _unstaked_amount: BalanceOf<T>,
  78. _remaining_imbalance: NegativeImbalance<T>,
  79. ) -> NegativeImbalance<T> {
  80. NegativeImbalance::<T>::zero()
  81. }
  82. fn slashed(
  83. _id: &T::StakeId,
  84. _slash_id: Option<T::SlashId>,
  85. _slahed_amount: BalanceOf<T>,
  86. _remaining_stake: BalanceOf<T>,
  87. _remaining_imbalance: NegativeImbalance<T>,
  88. ) -> NegativeImbalance<T> {
  89. NegativeImbalance::<T>::zero()
  90. }
  91. }
  92. /// Helper implementation so we can chain multiple handlers by grouping handlers in tuple pairs.
  93. /// For example for three handlers, A, B and C we can set the StakingEventHandler type on the trait to:
  94. /// type StakingEventHandler = ((A, B), C)
  95. /// Individual handlers are expected consume in full or in part the negative imbalance and return any unconsumed value.
  96. /// The unconsumed value is then passed to the next handler in the chain.
  97. impl<T: Trait, X: StakingEventsHandler<T>, Y: StakingEventsHandler<T>> StakingEventsHandler<T>
  98. for (X, Y)
  99. {
  100. fn unstaked(
  101. id: &T::StakeId,
  102. unstaked_amount: BalanceOf<T>,
  103. imbalance: NegativeImbalance<T>,
  104. ) -> NegativeImbalance<T> {
  105. let unused_imbalance = X::unstaked(id, unstaked_amount, imbalance);
  106. Y::unstaked(id, unstaked_amount, unused_imbalance)
  107. }
  108. fn slashed(
  109. id: &T::StakeId,
  110. slash_id: Option<T::SlashId>,
  111. slashed_amount: BalanceOf<T>,
  112. remaining_stake: BalanceOf<T>,
  113. imbalance: NegativeImbalance<T>,
  114. ) -> NegativeImbalance<T> {
  115. let unused_imbalance = X::slashed(id, slash_id, slashed_amount, remaining_stake, imbalance);
  116. Y::slashed(
  117. id,
  118. slash_id,
  119. slashed_amount,
  120. remaining_stake,
  121. unused_imbalance,
  122. )
  123. }
  124. }
  125. #[derive(Encode, Decode, Copy, Clone, Debug, Default, Eq, PartialEq)]
  126. pub struct Slash<BlockNumber, Balance> {
  127. /// The block where slashing was initiated.
  128. pub started_at_block: BlockNumber,
  129. /// Whether slashing is in active, or conversley paused state.
  130. /// Blocks are only counted towards slashing execution delay when active.
  131. pub is_active: bool,
  132. /// The number blocks which must be finalised while in the active period before the slashing can be executed
  133. pub blocks_remaining_in_active_period_for_slashing: BlockNumber,
  134. /// Amount to slash
  135. pub slash_amount: Balance,
  136. }
  137. #[derive(Encode, Decode, Debug, Default, Eq, PartialEq)]
  138. pub struct UnstakingState<BlockNumber> {
  139. /// The block where the unstaking was initiated
  140. pub started_at_block: BlockNumber,
  141. /// Whether unstaking is in active, or conversely paused state.
  142. /// Blocks are only counted towards unstaking period when active.
  143. pub is_active: bool,
  144. /// The number blocks which must be finalised while in the active period before the unstaking is finished
  145. pub blocks_remaining_in_active_period_for_unstaking: BlockNumber,
  146. }
  147. #[derive(Encode, Decode, Debug, Eq, PartialEq)]
  148. pub enum StakedStatus<BlockNumber> {
  149. /// Baseline staking status, nothing is happening.
  150. Normal,
  151. /// Unstaking is under way.
  152. Unstaking(UnstakingState<BlockNumber>),
  153. }
  154. impl<BlockNumber> Default for StakedStatus<BlockNumber> {
  155. fn default() -> Self {
  156. StakedStatus::Normal
  157. }
  158. }
  159. #[derive(Encode, Decode, Debug, Default, Eq, PartialEq)]
  160. pub struct StakedState<BlockNumber, Balance, SlashId: Ord> {
  161. /// Total amount of funds at stake.
  162. pub staked_amount: Balance,
  163. /// Status of the staking.
  164. pub staked_status: StakedStatus<BlockNumber>,
  165. /// SlashId to use for next Slash that is initiated.
  166. /// Will be incremented by one after adding a new Slash.
  167. pub next_slash_id: SlashId,
  168. /// All ongoing slashing.
  169. pub ongoing_slashes: BTreeMap<SlashId, Slash<BlockNumber, Balance>>,
  170. }
  171. impl<BlockNumber, Balance, SlashId> StakedState<BlockNumber, Balance, SlashId>
  172. where
  173. BlockNumber: SimpleArithmetic + Copy,
  174. Balance: SimpleArithmetic + Copy,
  175. SlashId: Ord + Copy,
  176. {
  177. /// Iterates over all ongoing slashes and decrements blocks_remaining_in_active_period_for_slashing of active slashes (advancing the timer).
  178. /// Returns true if there was at least one slashe that was active and had its timer advanced.
  179. fn advance_slashing_timer(&mut self) -> bool {
  180. let mut did_advance_timers = false;
  181. for (_slash_id, slash) in self.ongoing_slashes.iter_mut() {
  182. if slash.is_active
  183. && slash.blocks_remaining_in_active_period_for_slashing > Zero::zero()
  184. {
  185. slash.blocks_remaining_in_active_period_for_slashing -= One::one();
  186. did_advance_timers = true;
  187. }
  188. }
  189. did_advance_timers
  190. }
  191. /// Returns pair of slash_id and slashes that should be executed
  192. fn get_slashes_to_finalize(&mut self) -> Vec<(SlashId, Slash<BlockNumber, Balance>)> {
  193. let slashes_to_finalize = self
  194. .ongoing_slashes
  195. .iter()
  196. .filter(|(_, slash)| {
  197. slash.blocks_remaining_in_active_period_for_slashing == Zero::zero()
  198. })
  199. .map(|(slash_id, _)| *slash_id)
  200. .collect::<Vec<_>>();
  201. // remove and return the slashes
  202. slashes_to_finalize
  203. .iter()
  204. .map(|slash_id| {
  205. // assert!(self.ongoing_slashes.contains_key(slash_id))
  206. (*slash_id, self.ongoing_slashes.remove(slash_id).unwrap())
  207. })
  208. .collect()
  209. }
  210. /// Executes a Slash. If remaining at stake drops below the minimum_balance, it will slash the entire staked amount.
  211. /// Returns the actual slashed amount.
  212. fn apply_slash(&mut self, slash_amount: Balance, minimum_balance: Balance) -> Balance {
  213. // calculate how much to slash
  214. let mut slash_amount = if slash_amount > self.staked_amount {
  215. self.staked_amount
  216. } else {
  217. slash_amount
  218. };
  219. // apply the slashing
  220. self.staked_amount -= slash_amount;
  221. // don't leave less than minimum_balance at stake
  222. if self.staked_amount < minimum_balance {
  223. slash_amount += self.staked_amount;
  224. self.staked_amount = Zero::zero();
  225. }
  226. slash_amount
  227. }
  228. /// For all slahes that should be executed, will apply the Slash to the staked amount, and drop it from the ongoing slashes map.
  229. /// Returns a vector of the executed slashes outcome: (SlashId, Slashed Amount, Remaining Staked Amount)
  230. fn finalize_slashes(&mut self, minimum_balance: Balance) -> Vec<(SlashId, Balance, Balance)> {
  231. let mut finalized_slashes: Vec<(SlashId, Balance, Balance)> = vec![];
  232. for (slash_id, slash) in self.get_slashes_to_finalize().iter() {
  233. // apply the slashing and get back actual amount slashed
  234. let slashed_amount = self.apply_slash(slash.slash_amount, minimum_balance);
  235. finalized_slashes.push((*slash_id, slashed_amount, self.staked_amount));
  236. }
  237. finalized_slashes
  238. }
  239. }
  240. #[derive(Encode, Decode, Debug, Eq, PartialEq)]
  241. pub enum StakingStatus<BlockNumber, Balance, SlashId: Ord> {
  242. NotStaked,
  243. Staked(StakedState<BlockNumber, Balance, SlashId>),
  244. }
  245. impl<BlockNumber, Balance, SlashId: Ord> Default for StakingStatus<BlockNumber, Balance, SlashId> {
  246. fn default() -> Self {
  247. StakingStatus::NotStaked
  248. }
  249. }
  250. #[derive(Encode, Decode, Default, Debug, Eq, PartialEq)]
  251. pub struct Stake<BlockNumber, Balance, SlashId: Ord> {
  252. /// When role was created
  253. pub created: BlockNumber,
  254. /// Status of any possible ongoing staking
  255. pub staking_status: StakingStatus<BlockNumber, Balance, SlashId>,
  256. }
  257. impl<BlockNumber, Balance, SlashId> Stake<BlockNumber, Balance, SlashId>
  258. where
  259. BlockNumber: Copy + SimpleArithmetic + Zero,
  260. Balance: Copy + SimpleArithmetic,
  261. SlashId: Copy + Ord + Zero + One,
  262. {
  263. fn new(created_at: BlockNumber) -> Self {
  264. Self {
  265. created: created_at,
  266. staking_status: StakingStatus::NotStaked,
  267. }
  268. }
  269. fn is_not_staked(&self) -> bool {
  270. self.staking_status == StakingStatus::NotStaked
  271. }
  272. /// If staking status is Staked and not currently Unstaking it will increase the staked amount by value.
  273. /// On success returns new total staked value.
  274. /// Increasing stake by zero is an error.
  275. fn increase_stake(&mut self, value: Balance) -> Result<Balance, IncreasingStakeError> {
  276. ensure!(
  277. value > Zero::zero(),
  278. IncreasingStakeError::CannotChangeStakeByZero
  279. );
  280. match self.staking_status {
  281. StakingStatus::Staked(ref mut staked_state) => match staked_state.staked_status {
  282. StakedStatus::Normal => {
  283. staked_state.staked_amount += value;
  284. Ok(staked_state.staked_amount)
  285. }
  286. _ => Err(IncreasingStakeError::CannotIncreaseStakeWhileUnstaking),
  287. },
  288. _ => Err(IncreasingStakeError::NotStaked),
  289. }
  290. }
  291. /// If staking status is Staked and not currently Unstaking, and no ongoing slashes exist, it will decrease the amount at stake
  292. /// by provided value. If remaining at stake drops below the minimum_balance it will decrease the stake to zero.
  293. /// On success returns (the actual amount of stake decreased, the remaining amount at stake).
  294. /// Decreasing stake by zero is an error.
  295. fn decrease_stake(
  296. &mut self,
  297. value: Balance,
  298. minimum_balance: Balance,
  299. ) -> Result<(Balance, Balance), DecreasingStakeError> {
  300. // maybe StakeDecrease
  301. ensure!(
  302. value > Zero::zero(),
  303. DecreasingStakeError::CannotChangeStakeByZero
  304. );
  305. match self.staking_status {
  306. StakingStatus::Staked(ref mut staked_state) => match staked_state.staked_status {
  307. StakedStatus::Normal => {
  308. // prevent decreasing stake if there are any ongoing slashes (irrespective if active or not)
  309. if !staked_state.ongoing_slashes.is_empty() {
  310. return Err(DecreasingStakeError::CannotDecreaseStakeWhileOngoingSlahes);
  311. }
  312. if value > staked_state.staked_amount {
  313. return Err(DecreasingStakeError::InsufficientStake);
  314. }
  315. let stake_to_reduce = if staked_state.staked_amount - value < minimum_balance {
  316. // If staked amount would drop below minimum balance, deduct the entire stake
  317. staked_state.staked_amount
  318. } else {
  319. value
  320. };
  321. staked_state.staked_amount -= stake_to_reduce;
  322. Ok((stake_to_reduce, staked_state.staked_amount))
  323. }
  324. _ => Err(DecreasingStakeError::CannotDecreaseStakeWhileUnstaking),
  325. },
  326. _ => Err(DecreasingStakeError::NotStaked),
  327. }
  328. }
  329. fn start_staking(
  330. &mut self,
  331. value: Balance,
  332. minimum_balance: Balance,
  333. ) -> Result<(), StakingError> {
  334. ensure!(value > Zero::zero(), StakingError::CannotStakeZero);
  335. ensure!(
  336. value >= minimum_balance,
  337. StakingError::CannotStakeLessThanMinimumBalance
  338. );
  339. if self.is_not_staked() {
  340. self.staking_status = StakingStatus::Staked(StakedState {
  341. staked_amount: value,
  342. next_slash_id: Zero::zero(),
  343. ongoing_slashes: BTreeMap::new(),
  344. staked_status: StakedStatus::Normal,
  345. });
  346. Ok(())
  347. } else {
  348. Err(StakingError::AlreadyStaked)
  349. }
  350. }
  351. fn slash_immediate(
  352. &mut self,
  353. slash_amount: Balance,
  354. minimum_balance: Balance,
  355. ) -> Result<(Balance, Balance), ImmediateSlashingError> {
  356. ensure!(
  357. slash_amount > Zero::zero(),
  358. ImmediateSlashingError::SlashAmountShouldBeGreaterThanZero
  359. );
  360. match self.staking_status {
  361. StakingStatus::Staked(ref mut staked_state) => {
  362. // irrespective of wether we are unstaking or not, slash!
  363. let actually_slashed = staked_state.apply_slash(slash_amount, minimum_balance);
  364. let remaining_stake = staked_state.staked_amount;
  365. Ok((actually_slashed, remaining_stake))
  366. }
  367. // can't slash if not staked
  368. _ => Err(ImmediateSlashingError::NotStaked),
  369. }
  370. }
  371. fn initiate_slashing(
  372. &mut self,
  373. slash_amount: Balance,
  374. slash_period: BlockNumber,
  375. now: BlockNumber,
  376. ) -> Result<SlashId, InitiateSlashingError> {
  377. ensure!(
  378. slash_period > Zero::zero(),
  379. InitiateSlashingError::SlashPeriodShouldBeGreaterThanZero
  380. );
  381. ensure!(
  382. slash_amount > Zero::zero(),
  383. InitiateSlashingError::SlashAmountShouldBeGreaterThanZero
  384. );
  385. match self.staking_status {
  386. StakingStatus::Staked(ref mut staked_state) => {
  387. let slash_id = staked_state.next_slash_id;
  388. staked_state.next_slash_id = slash_id + One::one();
  389. staked_state.ongoing_slashes.insert(
  390. slash_id,
  391. Slash {
  392. is_active: true,
  393. blocks_remaining_in_active_period_for_slashing: slash_period,
  394. slash_amount,
  395. started_at_block: now,
  396. },
  397. );
  398. // pause Unstaking if unstaking is active
  399. if let StakedStatus::Unstaking(ref mut unstaking_state) = staked_state.staked_status
  400. {
  401. unstaking_state.is_active = false;
  402. }
  403. Ok(slash_id)
  404. }
  405. _ => Err(InitiateSlashingError::NotStaked),
  406. }
  407. }
  408. fn pause_slashing(&mut self, slash_id: &SlashId) -> Result<(), PauseSlashingError> {
  409. match self.staking_status {
  410. StakingStatus::Staked(ref mut staked_state) => {
  411. match staked_state.ongoing_slashes.get_mut(slash_id) {
  412. Some(ref mut slash) => {
  413. if slash.is_active {
  414. slash.is_active = false;
  415. Ok(())
  416. } else {
  417. Err(PauseSlashingError::AlreadyPaused)
  418. }
  419. }
  420. _ => Err(PauseSlashingError::SlashNotFound),
  421. }
  422. }
  423. _ => Err(PauseSlashingError::NotStaked),
  424. }
  425. }
  426. fn resume_slashing(&mut self, slash_id: &SlashId) -> Result<(), ResumeSlashingError> {
  427. match self.staking_status {
  428. StakingStatus::Staked(ref mut staked_state) => {
  429. match staked_state.ongoing_slashes.get_mut(slash_id) {
  430. Some(ref mut slash) => {
  431. if slash.is_active {
  432. Err(ResumeSlashingError::NotPaused)
  433. } else {
  434. slash.is_active = true;
  435. Ok(())
  436. }
  437. }
  438. _ => Err(ResumeSlashingError::SlashNotFound),
  439. }
  440. }
  441. _ => Err(ResumeSlashingError::NotStaked),
  442. }
  443. }
  444. fn cancel_slashing(&mut self, slash_id: &SlashId) -> Result<(), CancelSlashingError> {
  445. match self.staking_status {
  446. StakingStatus::Staked(ref mut staked_state) => {
  447. if staked_state.ongoing_slashes.remove(slash_id).is_none() {
  448. return Err(CancelSlashingError::SlashNotFound);
  449. }
  450. // unpause unstaking on last ongoing slash cancelled
  451. if staked_state.ongoing_slashes.is_empty() {
  452. if let StakedStatus::Unstaking(ref mut unstaking_state) =
  453. staked_state.staked_status
  454. {
  455. unstaking_state.is_active = true;
  456. }
  457. }
  458. Ok(())
  459. }
  460. _ => Err(CancelSlashingError::NotStaked),
  461. }
  462. }
  463. fn unstake(&mut self) -> Result<Balance, UnstakingError> {
  464. let staked_amount = match self.staking_status {
  465. StakingStatus::Staked(ref staked_state) => {
  466. // prevent unstaking if there are any ongonig slashes (irrespective if active or not)
  467. if !staked_state.ongoing_slashes.is_empty() {
  468. return Err(UnstakingError::CannotUnstakeWhileSlashesOngoing);
  469. }
  470. if StakedStatus::Normal != staked_state.staked_status {
  471. return Err(UnstakingError::AlreadyUnstaking);
  472. }
  473. Ok(staked_state.staked_amount)
  474. }
  475. _ => Err(UnstakingError::NotStaked),
  476. }?;
  477. self.staking_status = StakingStatus::NotStaked;
  478. Ok(staked_amount)
  479. }
  480. fn initiate_unstaking(
  481. &mut self,
  482. unstaking_period: BlockNumber,
  483. now: BlockNumber,
  484. ) -> Result<(), InitiateUnstakingError> {
  485. ensure!(
  486. unstaking_period > Zero::zero(),
  487. InitiateUnstakingError::UnstakingPeriodShouldBeGreaterThanZero
  488. );
  489. match self.staking_status {
  490. StakingStatus::Staked(ref mut staked_state) => {
  491. // prevent unstaking if there are any ongonig slashes (irrespective if active or not)
  492. if !staked_state.ongoing_slashes.is_empty() {
  493. return Err(InitiateUnstakingError::UnstakingError(
  494. UnstakingError::CannotUnstakeWhileSlashesOngoing,
  495. ));
  496. }
  497. if StakedStatus::Normal != staked_state.staked_status {
  498. return Err(InitiateUnstakingError::UnstakingError(
  499. UnstakingError::AlreadyUnstaking,
  500. ));
  501. }
  502. staked_state.staked_status = StakedStatus::Unstaking(UnstakingState {
  503. started_at_block: now,
  504. is_active: true,
  505. blocks_remaining_in_active_period_for_unstaking: unstaking_period,
  506. });
  507. Ok(())
  508. }
  509. _ => Err(InitiateUnstakingError::UnstakingError(
  510. UnstakingError::NotStaked,
  511. )),
  512. }
  513. }
  514. fn pause_unstaking(&mut self) -> Result<(), PauseUnstakingError> {
  515. match self.staking_status {
  516. StakingStatus::Staked(ref mut staked_state) => match staked_state.staked_status {
  517. StakedStatus::Unstaking(ref mut unstaking_state) => {
  518. if unstaking_state.is_active {
  519. unstaking_state.is_active = false;
  520. Ok(())
  521. } else {
  522. Err(PauseUnstakingError::AlreadyPaused)
  523. }
  524. }
  525. _ => Err(PauseUnstakingError::NotUnstaking),
  526. },
  527. _ => Err(PauseUnstakingError::NotStaked),
  528. }
  529. }
  530. fn resume_unstaking(&mut self) -> Result<(), ResumeUnstakingError> {
  531. match self.staking_status {
  532. StakingStatus::Staked(ref mut staked_state) => match staked_state.staked_status {
  533. StakedStatus::Unstaking(ref mut unstaking_state) => {
  534. if !unstaking_state.is_active {
  535. unstaking_state.is_active = true;
  536. Ok(())
  537. } else {
  538. Err(ResumeUnstakingError::NotPaused)
  539. }
  540. }
  541. _ => Err(ResumeUnstakingError::NotUnstaking),
  542. },
  543. _ => Err(ResumeUnstakingError::NotStaked),
  544. }
  545. }
  546. fn finalize_slashing(
  547. &mut self,
  548. minimum_balance: Balance,
  549. ) -> (bool, Vec<(SlashId, Balance, Balance)>) {
  550. match self.staking_status {
  551. StakingStatus::Staked(ref mut staked_state) => {
  552. // tick the slashing timer
  553. let did_update = staked_state.advance_slashing_timer();
  554. // finalize and apply slashes
  555. let slashed = staked_state.finalize_slashes(minimum_balance);
  556. (did_update, slashed)
  557. }
  558. _ => (false, vec![]),
  559. }
  560. }
  561. fn finalize_unstaking(&mut self) -> (bool, Option<Balance>) {
  562. let (did_update, unstaked) = match self.staking_status {
  563. StakingStatus::Staked(ref mut staked_state) => match staked_state.staked_status {
  564. StakedStatus::Unstaking(ref mut unstaking_state) => {
  565. // if all slashes were processed and there are no more active slashes
  566. // resume unstaking
  567. if staked_state.ongoing_slashes.is_empty() {
  568. unstaking_state.is_active = true;
  569. }
  570. // tick the unstaking timer
  571. if unstaking_state.is_active
  572. && unstaking_state.blocks_remaining_in_active_period_for_unstaking
  573. > Zero::zero()
  574. {
  575. // tick the unstaking timer
  576. unstaking_state.blocks_remaining_in_active_period_for_unstaking -=
  577. One::one();
  578. }
  579. // finalize unstaking
  580. if unstaking_state.blocks_remaining_in_active_period_for_unstaking
  581. == Zero::zero()
  582. {
  583. (true, Some(staked_state.staked_amount))
  584. } else {
  585. (unstaking_state.is_active, None)
  586. }
  587. }
  588. _ => (false, None),
  589. },
  590. _ => (false, None),
  591. };
  592. // if unstaking was finalized transition to NotStaked state
  593. if unstaked.is_some() {
  594. self.staking_status = StakingStatus::NotStaked;
  595. }
  596. (did_update, unstaked)
  597. }
  598. fn finalize_slashing_and_unstaking(
  599. &mut self,
  600. minimum_balance: Balance,
  601. ) -> (bool, Vec<(SlashId, Balance, Balance)>, Option<Balance>) {
  602. let (did_update_slashing_timers, slashed) = self.finalize_slashing(minimum_balance);
  603. let (did_update_unstaking_timer, unstaked) = self.finalize_unstaking();
  604. (
  605. did_update_slashing_timers || did_update_unstaking_timer,
  606. slashed,
  607. unstaked,
  608. )
  609. }
  610. }
  611. #[derive(Debug, Eq, PartialEq)]
  612. pub struct SlashImmediateOutcome<Balance, NegativeImbalance> {
  613. pub caused_unstake: bool,
  614. pub actually_slashed: Balance,
  615. pub remaining_stake: Balance,
  616. pub remaining_imbalance: NegativeImbalance,
  617. }
  618. decl_storage! {
  619. trait Store for Module<T: Trait> as StakePool {
  620. /// Maps identifiers to a stake.
  621. pub Stakes get(stakes): linked_map T::StakeId => Stake<T::BlockNumber, BalanceOf<T>, T::SlashId>;
  622. /// Identifier value for next stake, and count of total stakes created (not necessarily the number of current
  623. /// stakes in the Stakes map as stakes can be removed.)
  624. pub StakesCreated get(stakes_created): T::StakeId;
  625. }
  626. }
  627. decl_module! {
  628. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  629. fn on_finalize(_now: T::BlockNumber) {
  630. Self::finalize_slashing_and_unstaking();
  631. }
  632. }
  633. }
  634. impl<T: Trait> Module<T> {
  635. /// The account ID of theis module which holds all the staked balance. (referred to as the stake pool)
  636. ///
  637. /// This actually does computation. If you need to keep using it, then make sure you cache the
  638. /// value and only call this once. Is it deterministic?
  639. pub fn stake_pool_account_id() -> T::AccountId {
  640. ModuleId(T::StakePoolId::get()).into_account()
  641. }
  642. pub fn stake_pool_balance() -> BalanceOf<T> {
  643. T::Currency::free_balance(&Self::stake_pool_account_id())
  644. }
  645. /// Adds a new Stake which is NotStaked, created at given block, into stakes map.
  646. pub fn create_stake() -> T::StakeId {
  647. let stake_id = Self::stakes_created();
  648. <StakesCreated<T>>::put(stake_id + One::one());
  649. <Stakes<T>>::insert(&stake_id, Stake::new(<system::Module<T>>::block_number()));
  650. stake_id
  651. }
  652. /// Given that stake with id exists in stakes and is NotStaked, remove from stakes.
  653. pub fn remove_stake(stake_id: &T::StakeId) -> Result<(), StakeActionError<StakingError>> {
  654. let stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  655. ensure!(
  656. stake.is_not_staked(),
  657. StakeActionError::Error(StakingError::AlreadyStaked)
  658. );
  659. <Stakes<T>>::remove(stake_id);
  660. Ok(())
  661. }
  662. /// Dry run to see if staking can be initiated for the specified stake id. This should
  663. /// be called before stake() to make sure staking is possible before withdrawing funds.
  664. pub fn ensure_can_stake(
  665. stake_id: &T::StakeId,
  666. value: BalanceOf<T>,
  667. ) -> Result<(), StakeActionError<StakingError>> {
  668. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  669. stake
  670. .start_staking(value, T::Currency::minimum_balance())
  671. .err()
  672. .map_or(Ok(()), |err| Err(StakeActionError::Error(err)))
  673. }
  674. /// Provided the stake exists and is in state NotStaked the value is transferred
  675. /// to the module's account, and the corresponding staked_balance is set to this amount in the new Staked state.
  676. /// On error, as the negative imbalance is not returned to the caller, it is the caller's responsibility to return the funds
  677. /// back to the source (by creating a new positive imbalance)
  678. pub fn stake(
  679. stake_id: &T::StakeId,
  680. imbalance: NegativeImbalance<T>,
  681. ) -> Result<(), StakeActionError<StakingError>> {
  682. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  683. let value = imbalance.peek();
  684. stake.start_staking(value, T::Currency::minimum_balance())?;
  685. <Stakes<T>>::insert(stake_id, stake);
  686. Self::deposit_funds_into_stake_pool(imbalance);
  687. Ok(())
  688. }
  689. pub fn stake_from_account(
  690. stake_id: &T::StakeId,
  691. source_account_id: &T::AccountId,
  692. value: BalanceOf<T>,
  693. ) -> Result<(), StakeActionError<StakingFromAccountError>> {
  694. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  695. stake.start_staking(value, T::Currency::minimum_balance())?;
  696. // Its important to only do the transfer as the last step to ensure starting staking was possible.
  697. Self::transfer_funds_from_account_into_stake_pool(source_account_id, value)?;
  698. <Stakes<T>>::insert(stake_id, stake);
  699. Ok(())
  700. }
  701. /// Moves funds from specified account into the module's account
  702. fn transfer_funds_from_account_into_stake_pool(
  703. source: &T::AccountId,
  704. value: BalanceOf<T>,
  705. ) -> Result<(), TransferFromAccountError> {
  706. // We don't use T::Currency::transfer() to prevent fees being incurred.
  707. let negative_imbalance = T::Currency::withdraw(
  708. source,
  709. value,
  710. WithdrawReasons::all(),
  711. ExistenceRequirement::AllowDeath,
  712. )
  713. .map_err(|_err| TransferFromAccountError::InsufficientBalance)?;
  714. Self::deposit_funds_into_stake_pool(negative_imbalance);
  715. Ok(())
  716. }
  717. fn deposit_funds_into_stake_pool(imbalance: NegativeImbalance<T>) {
  718. // move the negative imbalance into the stake pool
  719. T::Currency::resolve_creating(&Self::stake_pool_account_id(), imbalance);
  720. }
  721. /// Moves funds from the module's account into specified account. Should never fail if used internally.
  722. /// Will panic! if value exceeds balance in the pool.
  723. fn transfer_funds_from_pool_into_account(destination: &T::AccountId, value: BalanceOf<T>) {
  724. let imbalance = Self::withdraw_funds_from_stake_pool(value);
  725. T::Currency::resolve_creating(destination, imbalance);
  726. }
  727. /// Withdraws value from the pool and returns a NegativeImbalance.
  728. /// As long as it is only called internally when executing slashes and unstaking, it
  729. /// should never fail as the pool balance is always in sync with total amount at stake.
  730. fn withdraw_funds_from_stake_pool(value: BalanceOf<T>) -> NegativeImbalance<T> {
  731. // We don't use T::Currency::transfer() to prevent fees being incurred.
  732. T::Currency::withdraw(
  733. &Self::stake_pool_account_id(),
  734. value,
  735. WithdrawReasons::all(),
  736. ExistenceRequirement::AllowDeath,
  737. )
  738. .expect("pool had less than expected funds!")
  739. }
  740. /// Dry run to see if the state of stake allows for increasing stake. This should be called
  741. /// to make sure increasing stake is possible before withdrawing funds.
  742. pub fn ensure_can_increase_stake(
  743. stake_id: &T::StakeId,
  744. value: BalanceOf<T>,
  745. ) -> Result<(), StakeActionError<IncreasingStakeError>> {
  746. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  747. stake
  748. .increase_stake(value)
  749. .err()
  750. .map_or(Ok(()), |err| Err(StakeActionError::Error(err)))
  751. }
  752. /// Provided the stake exists and is in state Staked.Normal, then the amount is transferred to the module's account,
  753. /// and the corresponding staked_amount is increased by the value. New value of staked_amount is returned.
  754. /// Caller should call check ensure_can_increase_stake() prior to avoid getting back an error. On error, as the negative imbalance
  755. /// is not returned to the caller, it is the caller's responsibility to return the funds back to the source (by creating a new positive imbalance)
  756. pub fn increase_stake(
  757. stake_id: &T::StakeId,
  758. imbalance: NegativeImbalance<T>,
  759. ) -> Result<BalanceOf<T>, StakeActionError<IncreasingStakeError>> {
  760. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  761. let total_staked_amount = stake.increase_stake(imbalance.peek())?;
  762. <Stakes<T>>::insert(stake_id, stake);
  763. Self::deposit_funds_into_stake_pool(imbalance);
  764. Ok(total_staked_amount)
  765. }
  766. /// Provided the stake exists and is in state Staked.Normal, and the given source account covers the amount,
  767. /// then the amount is transferred to the module's account, and the corresponding staked_amount is increased
  768. /// by the amount. New value of staked_amount is returned.
  769. pub fn increase_stake_from_account(
  770. stake_id: &T::StakeId,
  771. source_account_id: &T::AccountId,
  772. value: BalanceOf<T>,
  773. ) -> Result<BalanceOf<T>, StakeActionError<IncreasingStakeFromAccountError>> {
  774. // Compiler error when using macro: cannot infer type for `ErrorType`
  775. // let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  776. ensure!(
  777. <Stakes<T>>::exists(stake_id),
  778. StakeActionError::StakeNotFound
  779. );
  780. let mut stake = Self::stakes(stake_id);
  781. let total_staked_amount = stake.increase_stake(value)?;
  782. Self::transfer_funds_from_account_into_stake_pool(&source_account_id, value)?;
  783. <Stakes<T>>::insert(stake_id, stake);
  784. Ok(total_staked_amount)
  785. }
  786. pub fn ensure_can_decrease_stake(
  787. stake_id: &T::StakeId,
  788. value: BalanceOf<T>,
  789. ) -> Result<(), StakeActionError<DecreasingStakeError>> {
  790. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  791. stake
  792. .decrease_stake(value, T::Currency::minimum_balance())
  793. .err()
  794. .map_or(Ok(()), |err| Err(StakeActionError::Error(err)))
  795. }
  796. pub fn decrease_stake(
  797. stake_id: &T::StakeId,
  798. value: BalanceOf<T>,
  799. ) -> Result<(BalanceOf<T>, NegativeImbalance<T>), StakeActionError<DecreasingStakeError>> {
  800. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  801. let (deduct_from_pool, staked_amount) =
  802. stake.decrease_stake(value, T::Currency::minimum_balance())?;
  803. <Stakes<T>>::insert(stake_id, stake);
  804. let imbalance = Self::withdraw_funds_from_stake_pool(deduct_from_pool);
  805. Ok((staked_amount, imbalance))
  806. }
  807. /// Provided the stake exists and is in state Staked.Normal, and the given stake holds at least the value,
  808. /// then the value is transferred from the module's account to the destination_account, and the corresponding
  809. /// staked_amount is decreased by the value. New value of staked_amount is returned.
  810. pub fn decrease_stake_to_account(
  811. stake_id: &T::StakeId,
  812. destination_account_id: &T::AccountId,
  813. value: BalanceOf<T>,
  814. ) -> Result<BalanceOf<T>, StakeActionError<DecreasingStakeError>> {
  815. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  816. let (deduct_from_pool, staked_amount) =
  817. stake.decrease_stake(value, T::Currency::minimum_balance())?;
  818. <Stakes<T>>::insert(stake_id, stake);
  819. Self::transfer_funds_from_pool_into_account(&destination_account_id, deduct_from_pool);
  820. Ok(staked_amount)
  821. }
  822. /// Slashes a stake with immediate effect, returns the outcome of the slashing.
  823. /// Can optionally specify if slashing can result in immediate unstaking if staked amount
  824. /// after slashing goes to zero.
  825. pub fn slash_immediate(
  826. stake_id: &T::StakeId,
  827. slash_amount: BalanceOf<T>,
  828. unstake_on_zero_staked: bool,
  829. ) -> Result<
  830. SlashImmediateOutcome<BalanceOf<T>, NegativeImbalance<T>>,
  831. StakeActionError<ImmediateSlashingError>,
  832. > {
  833. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  834. // Get amount at stake before slashing to be used in unstaked event trigger
  835. let staked_amount_before_slash = ensure_staked_amount!(
  836. stake,
  837. StakeActionError::Error(ImmediateSlashingError::NotStaked)
  838. )?;
  839. let (actually_slashed, remaining_stake) =
  840. stake.slash_immediate(slash_amount, T::Currency::minimum_balance())?;
  841. let caused_unstake = unstake_on_zero_staked && remaining_stake == BalanceOf::<T>::zero();
  842. if caused_unstake {
  843. stake.staking_status = StakingStatus::NotStaked;
  844. }
  845. // Update state before calling handlers!
  846. <Stakes<T>>::insert(stake_id, stake);
  847. // Remove the slashed amount from the pool
  848. let slashed_imbalance = Self::withdraw_funds_from_stake_pool(actually_slashed);
  849. // Notify slashing event handler before unstaked handler.
  850. let remaining_imbalance_after_slash_handler = T::StakingEventsHandler::slashed(
  851. stake_id,
  852. None,
  853. actually_slashed,
  854. remaining_stake,
  855. slashed_imbalance,
  856. );
  857. let remaining_imbalance = if caused_unstake {
  858. // Notify unstaked handler with any remaining unused imbalance
  859. // from the slashing event handler
  860. T::StakingEventsHandler::unstaked(
  861. &stake_id,
  862. staked_amount_before_slash,
  863. remaining_imbalance_after_slash_handler,
  864. )
  865. } else {
  866. remaining_imbalance_after_slash_handler
  867. };
  868. Ok(SlashImmediateOutcome {
  869. caused_unstake,
  870. actually_slashed,
  871. remaining_stake,
  872. remaining_imbalance,
  873. })
  874. }
  875. /// Initiate a new slashing of a staked stake. Slashing begins at next block.
  876. pub fn initiate_slashing(
  877. stake_id: &T::StakeId,
  878. slash_amount: BalanceOf<T>,
  879. slash_period: T::BlockNumber,
  880. ) -> Result<T::SlashId, StakeActionError<InitiateSlashingError>> {
  881. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  882. let slash_id = stake.initiate_slashing(
  883. slash_amount,
  884. slash_period,
  885. <system::Module<T>>::block_number(),
  886. )?;
  887. <Stakes<T>>::insert(stake_id, stake);
  888. Ok(slash_id)
  889. }
  890. /// Pause an ongoing slashing
  891. pub fn pause_slashing(
  892. stake_id: &T::StakeId,
  893. slash_id: &T::SlashId,
  894. ) -> Result<(), StakeActionError<PauseSlashingError>> {
  895. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  896. stake.pause_slashing(slash_id)?;
  897. <Stakes<T>>::insert(stake_id, stake);
  898. Ok(())
  899. }
  900. /// Resume a currently paused ongoing slashing.
  901. pub fn resume_slashing(
  902. stake_id: &T::StakeId,
  903. slash_id: &T::SlashId,
  904. ) -> Result<(), StakeActionError<ResumeSlashingError>> {
  905. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  906. stake.resume_slashing(slash_id)?;
  907. <Stakes<T>>::insert(stake_id, stake);
  908. Ok(())
  909. }
  910. /// Cancel an ongoing slashing (regardless of whether its active or paused).
  911. pub fn cancel_slashing(
  912. stake_id: &T::StakeId,
  913. slash_id: &T::SlashId,
  914. ) -> Result<(), StakeActionError<CancelSlashingError>> {
  915. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  916. stake.cancel_slashing(slash_id)?;
  917. <Stakes<T>>::insert(stake_id, stake);
  918. Ok(())
  919. }
  920. /// Initiate unstaking of a Staked stake.
  921. pub fn initiate_unstaking(
  922. stake_id: &T::StakeId,
  923. unstaking_period: Option<T::BlockNumber>,
  924. ) -> Result<(), StakeActionError<InitiateUnstakingError>> {
  925. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  926. if let Some(unstaking_period) = unstaking_period {
  927. stake.initiate_unstaking(unstaking_period, <system::Module<T>>::block_number())?;
  928. <Stakes<T>>::insert(stake_id, stake);
  929. } else {
  930. let staked_amount = stake.unstake()?;
  931. <Stakes<T>>::insert(stake_id, stake);
  932. let imbalance = Self::withdraw_funds_from_stake_pool(staked_amount);
  933. let _ = T::StakingEventsHandler::unstaked(stake_id, staked_amount, imbalance);
  934. }
  935. Ok(())
  936. }
  937. /// Pause an ongoing Unstaking.
  938. pub fn pause_unstaking(
  939. stake_id: &T::StakeId,
  940. ) -> Result<(), StakeActionError<PauseUnstakingError>> {
  941. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  942. stake.pause_unstaking()?;
  943. <Stakes<T>>::insert(stake_id, stake);
  944. Ok(())
  945. }
  946. /// Resume a currently paused ongoing unstaking.
  947. pub fn resume_unstaking(
  948. stake_id: &T::StakeId,
  949. ) -> Result<(), StakeActionError<ResumeUnstakingError>> {
  950. let mut stake = ensure_stake_exists!(T, stake_id, StakeActionError::StakeNotFound)?;
  951. stake.resume_unstaking()?;
  952. <Stakes<T>>::insert(stake_id, stake);
  953. Ok(())
  954. }
  955. /// Handle timers for finalizing unstaking and slashing.
  956. /// Finalised unstaking results in the staked_balance in the given stake to removed from the pool, the corresponding
  957. /// imbalance is provided to the unstaked() hook in the StakingEventsHandler.
  958. /// Finalised slashing results in the staked_balance in the given stake being correspondingly reduced, and the imbalance
  959. /// is provided to the slashed() hook in the StakingEventsHandler.
  960. fn finalize_slashing_and_unstaking() {
  961. for (stake_id, ref mut stake) in <Stakes<T>>::enumerate() {
  962. let (updated, slashed, unstaked) =
  963. stake.finalize_slashing_and_unstaking(T::Currency::minimum_balance());
  964. // update the state before making external calls to StakingEventsHandler
  965. if updated {
  966. <Stakes<T>>::insert(stake_id, stake)
  967. }
  968. for (slash_id, slashed_amount, staked_amount) in slashed.into_iter() {
  969. // remove the slashed amount from the pool
  970. let imbalance = Self::withdraw_funds_from_stake_pool(slashed_amount);
  971. let _ = T::StakingEventsHandler::slashed(
  972. &stake_id,
  973. Some(slash_id),
  974. slashed_amount,
  975. staked_amount,
  976. imbalance,
  977. );
  978. }
  979. if let Some(staked_amount) = unstaked {
  980. // remove the unstaked amount from the pool
  981. let imbalance = Self::withdraw_funds_from_stake_pool(staked_amount);
  982. let _ = T::StakingEventsHandler::unstaked(&stake_id, staked_amount, imbalance);
  983. }
  984. }
  985. }
  986. }