mina_core/block/
prevalidate.rs

1use super::ArcBlockWithHash;
2use crate::constants::PROTOCOL_VERSION;
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug, Clone)]
6pub enum BlockPrevalidationError {
7    GenesisNotReady,
8    ReceivedTooEarly {
9        current_global_slot: u32,
10        block_global_slot: u32,
11    },
12    ReceivedTooLate {
13        current_global_slot: u32,
14        block_global_slot: u32,
15        delta: u32,
16    },
17    InvalidGenesisProtocolState,
18    InvalidProtocolVersion,
19    MismatchedProtocolVersion,
20    ConsantsMismatch,
21    InvalidDeltaBlockChainProof,
22}
23
24impl BlockPrevalidationError {
25    pub fn is_forever_invalid(&self) -> bool {
26        !matches!(self, Self::ReceivedTooEarly { .. })
27    }
28}
29
30pub fn validate_block_timing(
31    block: &ArcBlockWithHash,
32    genesis: &ArcBlockWithHash,
33    cur_global_slot: u32,
34    allow_block_too_late: bool,
35) -> Result<(), BlockPrevalidationError> {
36    let block_global_slot = block.global_slot();
37    let delta = genesis.constants().delta.as_u32();
38
39    if cur_global_slot < block_global_slot {
40        return Err(BlockPrevalidationError::ReceivedTooEarly {
41            current_global_slot: cur_global_slot,
42            block_global_slot,
43        });
44    } else if !allow_block_too_late && cur_global_slot.saturating_sub(block_global_slot) > delta {
45        return Err(BlockPrevalidationError::ReceivedTooLate {
46            current_global_slot: cur_global_slot,
47            block_global_slot,
48            delta,
49        });
50    }
51
52    Ok(())
53}
54
55pub fn validate_genesis_state(
56    block: &ArcBlockWithHash,
57    genesis: &ArcBlockWithHash,
58) -> Result<(), BlockPrevalidationError> {
59    if block.header().genesis_state_hash() != genesis.hash() {
60        return Err(BlockPrevalidationError::InvalidGenesisProtocolState);
61    }
62    Ok(())
63}
64
65pub fn validate_protocol_versions(block: &ArcBlockWithHash) -> Result<(), BlockPrevalidationError> {
66    let min_transaction_version = 1.into();
67    let v = &block.header().current_protocol_version;
68    let nv = block
69        .header()
70        .proposed_protocol_version_opt
71        .as_ref()
72        .unwrap_or(v);
73
74    // Our version values are unsigned, so there is no need to check that the
75    // other parts are not negative.
76    let valid =
77        v.transaction >= min_transaction_version && nv.transaction >= min_transaction_version;
78    if !valid {
79        return Err(BlockPrevalidationError::InvalidProtocolVersion);
80    }
81
82    let compatible =
83        v.transaction == PROTOCOL_VERSION.transaction && v.network == PROTOCOL_VERSION.network;
84    if !compatible {
85        return Err(BlockPrevalidationError::MismatchedProtocolVersion);
86    }
87
88    Ok(())
89}
90
91pub fn validate_constants(
92    block: &ArcBlockWithHash,
93    genesis: &ArcBlockWithHash,
94) -> Result<(), BlockPrevalidationError> {
95    // NOTE: currently these cannot change between blocks, but that
96    // may not always be true?
97    if block.constants() != genesis.constants() {
98        return Err(BlockPrevalidationError::ConsantsMismatch);
99    }
100    Ok(())
101}
102
103pub fn prevalidate_block(
104    block: &ArcBlockWithHash,
105    genesis: &ArcBlockWithHash,
106    cur_global_slot: u32,
107    allow_block_too_late: bool,
108) -> Result<(), BlockPrevalidationError> {
109    validate_block_timing(block, genesis, cur_global_slot, allow_block_too_late)?;
110    validate_genesis_state(block, genesis)?;
111    validate_protocol_versions(block)?;
112    validate_constants(block, genesis)?;
113
114    // TODO(tizoc): check for InvalidDeltaBlockChainProof
115    // <https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/mina_block/validation.ml#L369>
116    // <https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/transition_chain_verifier/transition_chain_verifier.ml>
117
118    Ok(())
119}