logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! Support for a step method.
//!
//! A step request executes auction code, slashes validators, evicts validators and distributes
//! rewards.
use std::{collections::BTreeMap, vec::Vec};

use casper_hashing::Digest;
use casper_types::{bytesrepr, CLValueError, EraId, ProtocolVersion, PublicKey};

use crate::{
    core::{engine_state::Error, execution, runtime::stack::RuntimeStackOverflow},
    shared::execution_journal::ExecutionJournal,
};

/// The definition of a slash item.
#[derive(Debug)]
pub struct SlashItem {
    /// The public key of the validator that will be slashed.
    pub validator_id: PublicKey,
}

impl SlashItem {
    /// Creates a new slash item.
    pub fn new(validator_id: PublicKey) -> Self {
        Self { validator_id }
    }
}

/// The definition of a reward item.
#[derive(Debug)]
pub struct RewardItem {
    /// The public key of the validator that will be rewarded.
    pub validator_id: PublicKey,
    /// Amount of motes that will be distributed as rewards.
    pub value: u64,
}

impl RewardItem {
    /// Creates new reward item.
    pub fn new(validator_id: PublicKey, value: u64) -> Self {
        Self {
            validator_id,
            value,
        }
    }
}

/// The definition of an evict item.
#[derive(Debug)]
pub struct EvictItem {
    /// The public key of the validator that will be evicted.
    pub validator_id: PublicKey,
}

impl EvictItem {
    /// Creates new evict item.
    pub fn new(validator_id: PublicKey) -> Self {
        Self { validator_id }
    }
}

/// Representation of a step request.
#[derive(Debug)]
pub struct StepRequest {
    /// State root hash.
    pub pre_state_hash: Digest,
    /// Protocol version for this request.
    pub protocol_version: ProtocolVersion,
    /// List of validators to be slashed.
    ///
    /// A slashed validator is removed from the next validator set.
    pub slash_items: Vec<SlashItem>,
    /// List of validators that will be rewarded.
    pub reward_items: Vec<RewardItem>,
    /// List of validators to be evicted.
    ///
    /// Compared to a slashing, evictions are deactivating a given validator, but his stake is
    /// unchanged. A further re-activation is possible.
    pub evict_items: Vec<EvictItem>,
    /// Specifies which era validators will be returned based on `next_era_id`.
    ///
    /// Intended use is to always specify the current era id + 1 which will return computed era at
    /// the end of this step request.
    pub next_era_id: EraId,
    /// Timestamp in milliseconds representing end of the current era.
    pub era_end_timestamp_millis: u64,
}

impl StepRequest {
    /// Creates new step request.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        pre_state_hash: Digest,
        protocol_version: ProtocolVersion,
        slash_items: Vec<SlashItem>,
        reward_items: Vec<RewardItem>,
        evict_items: Vec<EvictItem>,
        next_era_id: EraId,
        era_end_timestamp_millis: u64,
    ) -> Self {
        Self {
            pre_state_hash,
            protocol_version,
            slash_items,
            reward_items,
            evict_items,
            next_era_id,
            era_end_timestamp_millis,
        }
    }

    /// Returns list of slashed validators.
    pub fn slashed_validators(&self) -> Vec<PublicKey> {
        self.slash_items
            .iter()
            .map(|si| si.validator_id.clone())
            .collect()
    }

    /// Returns all reward factors.
    pub fn reward_factors(&self) -> Result<BTreeMap<PublicKey, u64>, bytesrepr::Error> {
        let mut ret = BTreeMap::new();
        for reward_item in &self.reward_items {
            ret.insert(reward_item.validator_id.clone(), reward_item.value);
        }
        Ok(ret)
    }
}

/// Representation of all possible failures of a step request.
#[derive(Debug, thiserror::Error)]
pub enum StepError {
    /// Invalid state root hash.
    #[error("Root not found: {0:?}")]
    RootNotFound(Digest),
    /// Error creating a tracking copy instance.
    #[error("Tracking copy error: {0}")]
    TrackingCopyError(Error),
    #[error("Get contract error: {0}")]
    /// Error getting a system contract.
    GetContractError(Error),
    /// Error retrieving a system module.
    #[error("Get system module error: {0}")]
    GetSystemModuleError(Error),
    /// Error executing a slashing operation.
    #[error("Slashing error: {0}")]
    SlashingError(Error),
    /// Error executing the auction contract.
    #[error("Auction error: {0}")]
    AuctionError(Error),
    /// Error executing a distribute operation.
    #[error("Distribute error: {0}")]
    DistributeError(Error),
    /// Invalid protocol version.
    #[error("Invalid protocol version: {0}")]
    InvalidProtocolVersion(ProtocolVersion),
    /// Error while (de)serializing data.
    #[error("{0}")]
    BytesRepr(bytesrepr::Error),
    /// Error converting `CLValue`.
    #[error("{0}")]
    CLValueError(CLValueError),
    #[error("Other engine state error: {0}")]
    /// Other engine state error.
    OtherEngineStateError(#[from] Error),
    /// Execution error.
    #[error(transparent)]
    ExecutionError(#[from] execution::Error),
}

impl From<bytesrepr::Error> for StepError {
    fn from(error: bytesrepr::Error) -> Self {
        StepError::BytesRepr(error)
    }
}

impl From<CLValueError> for StepError {
    fn from(error: CLValueError) -> Self {
        StepError::CLValueError(error)
    }
}

impl From<RuntimeStackOverflow> for StepError {
    fn from(overflow: RuntimeStackOverflow) -> Self {
        StepError::OtherEngineStateError(Error::from(overflow))
    }
}

/// Represents a successfully executed step request.
#[derive(Debug)]
pub struct StepSuccess {
    /// New state root hash generated after effects were applied.
    pub post_state_hash: Digest,
    /// Effects of executing a step request.
    pub execution_journal: ExecutionJournal,
}