1use serde::{Deserialize, Serialize};
2
3use hotmint_types::crypto::PublicKey;
4use hotmint_types::validator::ValidatorId;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ValidatorState {
9 pub id: ValidatorId,
10 pub public_key: PublicKey,
11 pub self_stake: u64,
13 pub delegated_stake: u64,
15 pub score: u32,
17 pub jailed: bool,
19 pub jail_until_height: u64,
21}
22
23impl ValidatorState {
24 pub fn total_stake(&self) -> u64 {
26 self.self_stake.saturating_add(self.delegated_stake)
27 }
28
29 pub fn voting_power(&self) -> u64 {
31 if self.jailed { 0 } else { self.total_stake() }
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct StakeEntry {
38 pub amount: u64,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum SlashReason {
44 DoubleSign,
46 Downtime,
48}
49
50#[derive(Debug, Clone)]
52pub struct SlashResult {
53 pub self_slashed: u64,
55 pub delegated_slashed: u64,
57 pub jailed: bool,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct UnbondingEntry {
67 pub staker: Vec<u8>,
68 pub validator: ValidatorId,
69 pub amount: u64,
70 pub completion_height: u64,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct StakingConfig {
77 pub max_validators: usize,
79 pub min_self_stake: u64,
81 pub slash_rate_double_sign: u32,
83 pub slash_rate_downtime: u32,
85 pub jail_duration: u64,
87 pub initial_score: u32,
89 pub max_score: u32,
91 pub block_reward: u64,
93 pub unbonding_period: u64,
95}
96
97impl StakingConfig {
98 pub fn validate(&self) -> ruc::Result<()> {
99 if self.max_validators == 0 {
100 return Err(ruc::eg!("max_validators must be > 0"));
101 }
102 if self.slash_rate_double_sign > 10_000 {
103 return Err(ruc::eg!(
104 "slash_rate_double_sign must be <= 10000 (basis points)"
105 ));
106 }
107 if self.slash_rate_downtime > 10_000 {
108 return Err(ruc::eg!(
109 "slash_rate_downtime must be <= 10000 (basis points)"
110 ));
111 }
112 if self.initial_score > self.max_score {
113 return Err(ruc::eg!("initial_score must be <= max_score"));
114 }
115 Ok(())
116 }
117}
118
119impl Default for StakingConfig {
120 fn default() -> Self {
121 Self {
122 max_validators: 100,
123 min_self_stake: 1000,
124 slash_rate_double_sign: 500, slash_rate_downtime: 100, jail_duration: 1000,
127 initial_score: 10_000,
128 max_score: 10_000,
129 block_reward: 100,
130 unbonding_period: 1000,
131 }
132 }
133}