near_primitives/
epoch_block_info.rs

1use crate::block_header::BlockHeader;
2use crate::stateless_validation::chunk_endorsements_bitmap::ChunkEndorsementsBitmap;
3use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter};
4use crate::types::{AccountId, EpochId, ValidatorStakeV1};
5use borsh::{BorshDeserialize, BorshSerialize};
6use near_primitives_core::hash::CryptoHash;
7use near_primitives_core::types::{Balance, BlockHeight, ProtocolVersion};
8use near_schema_checker_lib::ProtocolSchema;
9use std::collections::HashMap;
10
11/// Information per each block.
12#[derive(
13    BorshSerialize, BorshDeserialize, Eq, PartialEq, Clone, Debug, serde::Serialize, ProtocolSchema,
14)]
15pub enum BlockInfo {
16    V1(BlockInfoV1),
17    V2(BlockInfoV2),
18    V3(BlockInfoV3),
19}
20
21impl Default for BlockInfo {
22    fn default() -> Self {
23        Self::V3(BlockInfoV3::default())
24    }
25}
26
27impl BlockInfo {
28    #[allow(deprecated)]
29    pub fn new(
30        hash: CryptoHash,
31        height: BlockHeight,
32        last_finalized_height: BlockHeight,
33        last_final_block_hash: CryptoHash,
34        prev_hash: CryptoHash,
35        proposals: Vec<ValidatorStake>,
36        validator_mask: Vec<bool>,
37        total_supply: Balance,
38        latest_protocol_version: ProtocolVersion,
39        timestamp_nanosec: u64,
40        chunk_endorsements: Option<ChunkEndorsementsBitmap>,
41    ) -> Self {
42        if let Some(chunk_endorsements) = chunk_endorsements {
43            Self::V3(BlockInfoV3 {
44                hash,
45                height,
46                last_finalized_height,
47                last_final_block_hash,
48                prev_hash,
49                proposals,
50                chunk_mask: validator_mask,
51                latest_protocol_version,
52                slashed: HashMap::new(),
53                total_supply,
54                epoch_first_block: Default::default(),
55                epoch_id: Default::default(),
56                timestamp_nanosec,
57                chunk_endorsements,
58            })
59        } else {
60            Self::V2(BlockInfoV2 {
61                hash,
62                height,
63                last_finalized_height,
64                last_final_block_hash,
65                prev_hash,
66                proposals,
67                chunk_mask: validator_mask,
68                latest_protocol_version,
69                slashed: HashMap::new(),
70                total_supply,
71                epoch_first_block: Default::default(),
72                epoch_id: Default::default(),
73                timestamp_nanosec,
74            })
75        }
76    }
77
78    pub fn from_header(header: &BlockHeader, last_finalized_height: BlockHeight) -> Self {
79        BlockInfo::new(
80            *header.hash(),
81            header.height(),
82            last_finalized_height,
83            *header.last_final_block(),
84            *header.prev_hash(),
85            header.prev_validator_proposals().collect(),
86            header.chunk_mask().to_vec(),
87            header.total_supply(),
88            header.latest_protocol_version(),
89            header.raw_timestamp(),
90            header.chunk_endorsements().cloned(),
91        )
92    }
93
94    // TODO(#11900): Remove this and use `from_header` only, when endorsements bitmap is added to the BlockHeader.
95    pub fn from_header_and_endorsements(
96        header: &BlockHeader,
97        last_finalized_height: BlockHeight,
98        chunk_endorsements: Option<ChunkEndorsementsBitmap>,
99    ) -> Self {
100        BlockInfo::new(
101            *header.hash(),
102            header.height(),
103            last_finalized_height,
104            *header.last_final_block(),
105            *header.prev_hash(),
106            header.prev_validator_proposals().collect(),
107            header.chunk_mask().to_vec(),
108            header.total_supply(),
109            header.latest_protocol_version(),
110            header.raw_timestamp(),
111            header.chunk_endorsements().cloned().or(chunk_endorsements),
112        )
113    }
114
115    #[inline]
116    pub fn proposals_iter(&self) -> ValidatorStakeIter {
117        match self {
118            Self::V1(info) => ValidatorStakeIter::v1(&info.proposals),
119            Self::V2(info) => ValidatorStakeIter::new(&info.proposals),
120            Self::V3(info) => ValidatorStakeIter::new(&info.proposals),
121        }
122    }
123
124    #[inline]
125    pub fn hash(&self) -> &CryptoHash {
126        match self {
127            Self::V1(info) => &info.hash,
128            Self::V2(info) => &info.hash,
129            Self::V3(info) => &info.hash,
130        }
131    }
132
133    #[inline]
134    pub fn height(&self) -> BlockHeight {
135        match self {
136            Self::V1(info) => info.height,
137            Self::V2(info) => info.height,
138            Self::V3(info) => info.height,
139        }
140    }
141
142    #[inline]
143    pub fn last_finalized_height(&self) -> BlockHeight {
144        match self {
145            Self::V1(info) => info.last_finalized_height,
146            Self::V2(info) => info.last_finalized_height,
147            Self::V3(info) => info.last_finalized_height,
148        }
149    }
150
151    #[inline]
152    pub fn last_final_block_hash(&self) -> &CryptoHash {
153        match self {
154            Self::V1(info) => &info.last_final_block_hash,
155            Self::V2(info) => &info.last_final_block_hash,
156            Self::V3(info) => &info.last_final_block_hash,
157        }
158    }
159
160    #[inline]
161    pub fn prev_hash(&self) -> &CryptoHash {
162        match self {
163            Self::V1(info) => &info.prev_hash,
164            Self::V2(info) => &info.prev_hash,
165            Self::V3(info) => &info.prev_hash,
166        }
167    }
168
169    #[inline]
170    pub fn is_genesis(&self) -> bool {
171        self.prev_hash() == &CryptoHash::default()
172    }
173
174    #[inline]
175    pub fn epoch_first_block(&self) -> &CryptoHash {
176        match self {
177            Self::V1(info) => &info.epoch_first_block,
178            Self::V2(info) => &info.epoch_first_block,
179            Self::V3(info) => &info.epoch_first_block,
180        }
181    }
182
183    #[inline]
184    pub fn epoch_first_block_mut(&mut self) -> &mut CryptoHash {
185        match self {
186            Self::V1(info) => &mut info.epoch_first_block,
187            Self::V2(info) => &mut info.epoch_first_block,
188            Self::V3(info) => &mut info.epoch_first_block,
189        }
190    }
191
192    #[inline]
193    pub fn epoch_id(&self) -> &EpochId {
194        match self {
195            Self::V1(info) => &info.epoch_id,
196            Self::V2(info) => &info.epoch_id,
197            Self::V3(info) => &info.epoch_id,
198        }
199    }
200
201    #[inline]
202    pub fn epoch_id_mut(&mut self) -> &mut EpochId {
203        match self {
204            Self::V1(info) => &mut info.epoch_id,
205            Self::V2(info) => &mut info.epoch_id,
206            Self::V3(info) => &mut info.epoch_id,
207        }
208    }
209
210    #[inline]
211    pub fn chunk_mask(&self) -> &[bool] {
212        match self {
213            Self::V1(info) => &info.chunk_mask,
214            Self::V2(info) => &info.chunk_mask,
215            Self::V3(info) => &info.chunk_mask,
216        }
217    }
218
219    #[inline]
220    pub fn latest_protocol_version(&self) -> &ProtocolVersion {
221        match self {
222            Self::V1(info) => &info.latest_protocol_version,
223            Self::V2(info) => &info.latest_protocol_version,
224            Self::V3(info) => &info.latest_protocol_version,
225        }
226    }
227
228    #[inline]
229    pub fn total_supply(&self) -> &Balance {
230        match self {
231            Self::V1(info) => &info.total_supply,
232            Self::V2(info) => &info.total_supply,
233            Self::V3(info) => &info.total_supply,
234        }
235    }
236
237    #[inline]
238    pub fn timestamp_nanosec(&self) -> &u64 {
239        match self {
240            Self::V1(info) => &info.timestamp_nanosec,
241            Self::V2(info) => &info.timestamp_nanosec,
242            Self::V3(info) => &info.timestamp_nanosec,
243        }
244    }
245
246    #[inline]
247    pub fn chunk_endorsements(&self) -> Option<&ChunkEndorsementsBitmap> {
248        match self {
249            Self::V1(_) => None,
250            Self::V2(_) => None,
251            Self::V3(info) => Some(&info.chunk_endorsements),
252        }
253    }
254}
255
256// V2 -> V3: Add chunk_endorsements bitmap
257#[derive(
258    Default,
259    BorshSerialize,
260    BorshDeserialize,
261    Eq,
262    PartialEq,
263    Clone,
264    Debug,
265    serde::Serialize,
266    ProtocolSchema,
267)]
268pub struct BlockInfoV3 {
269    pub hash: CryptoHash,
270    pub height: BlockHeight,
271    pub last_finalized_height: BlockHeight,
272    pub last_final_block_hash: CryptoHash,
273    pub prev_hash: CryptoHash,
274    pub epoch_first_block: CryptoHash,
275    pub epoch_id: EpochId,
276    pub proposals: Vec<ValidatorStake>,
277    pub chunk_mask: Vec<bool>,
278    /// Latest protocol version this validator observes.
279    pub latest_protocol_version: ProtocolVersion,
280    /// Validators slashed since the start of epoch or in previous epoch.
281    #[deprecated]
282    pub slashed: HashMap<AccountId, SlashState>,
283    /// Total supply at this block.
284    pub total_supply: Balance,
285    pub timestamp_nanosec: u64,
286    pub chunk_endorsements: ChunkEndorsementsBitmap,
287}
288
289// V1 -> V2: Use versioned ValidatorStake structure in proposals
290#[derive(
291    Default,
292    BorshSerialize,
293    BorshDeserialize,
294    Eq,
295    PartialEq,
296    Clone,
297    Debug,
298    serde::Serialize,
299    ProtocolSchema,
300)]
301pub struct BlockInfoV2 {
302    pub hash: CryptoHash,
303    pub height: BlockHeight,
304    pub last_finalized_height: BlockHeight,
305    pub last_final_block_hash: CryptoHash,
306    pub prev_hash: CryptoHash,
307    pub epoch_first_block: CryptoHash,
308    pub epoch_id: EpochId,
309    pub proposals: Vec<ValidatorStake>,
310    pub chunk_mask: Vec<bool>,
311    /// Latest protocol version this validator observes.
312    pub latest_protocol_version: ProtocolVersion,
313    /// Validators slashed since the start of epoch or in previous epoch.
314    #[deprecated]
315    pub slashed: HashMap<AccountId, SlashState>,
316    /// Total supply at this block.
317    pub total_supply: Balance,
318    pub timestamp_nanosec: u64,
319}
320
321/// Information per each block.
322#[derive(
323    Default,
324    BorshSerialize,
325    BorshDeserialize,
326    Eq,
327    PartialEq,
328    Clone,
329    Debug,
330    serde::Serialize,
331    ProtocolSchema,
332)]
333pub struct BlockInfoV1 {
334    pub hash: CryptoHash,
335    pub height: BlockHeight,
336    pub last_finalized_height: BlockHeight,
337    pub last_final_block_hash: CryptoHash,
338    pub prev_hash: CryptoHash,
339    pub epoch_first_block: CryptoHash,
340    pub epoch_id: EpochId,
341    pub proposals: Vec<ValidatorStakeV1>,
342    pub chunk_mask: Vec<bool>,
343    /// Latest protocol version this validator observes.
344    pub latest_protocol_version: ProtocolVersion,
345    /// Validators slashed since the start of epoch or in previous epoch.
346    #[deprecated]
347    pub slashed: HashMap<AccountId, SlashState>,
348    /// Total supply at this block.
349    pub total_supply: Balance,
350    pub timestamp_nanosec: u64,
351}
352
353impl BlockInfoV1 {
354    #[allow(deprecated)]
355    pub fn new(
356        hash: CryptoHash,
357        height: BlockHeight,
358        last_finalized_height: BlockHeight,
359        last_final_block_hash: CryptoHash,
360        prev_hash: CryptoHash,
361        proposals: Vec<ValidatorStakeV1>,
362        validator_mask: Vec<bool>,
363        total_supply: Balance,
364        latest_protocol_version: ProtocolVersion,
365        timestamp_nanosec: u64,
366    ) -> Self {
367        Self {
368            hash,
369            height,
370            last_finalized_height,
371            last_final_block_hash,
372            prev_hash,
373            proposals,
374            chunk_mask: validator_mask,
375            latest_protocol_version,
376            slashed: HashMap::new(),
377            total_supply,
378            epoch_first_block: Default::default(),
379            epoch_id: Default::default(),
380            timestamp_nanosec,
381        }
382    }
383}
384
385/// State that a slashed validator can be in.
386#[derive(
387    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
388)]
389pub enum SlashState {
390    /// Double Sign, will be partially slashed.
391    DoubleSign,
392    /// Malicious behavior but is already slashed (tokens taken away from account).
393    AlreadySlashed,
394    /// All other cases (tokens should be entirely slashed),
395    Other,
396}