openmina_core/block/
prevalidate.rs1use serde::{Deserialize, Serialize};
2
3use super::ArcBlockWithHash;
4use crate::constants::PROTOCOL_VERSION;
5
6#[derive(Serialize, Deserialize, Debug, Clone)]
7pub enum BlockPrevalidationError {
8 GenesisNotReady,
9 ReceivedTooEarly {
10 current_global_slot: u32,
11 block_global_slot: u32,
12 },
13 ReceivedTooLate {
14 current_global_slot: u32,
15 block_global_slot: u32,
16 delta: u32,
17 },
18 InvalidGenesisProtocolState,
19 InvalidProtocolVersion,
20 MismatchedProtocolVersion,
21 ConsantsMismatch,
22 InvalidDeltaBlockChainProof,
23}
24
25impl BlockPrevalidationError {
26 pub fn is_forever_invalid(&self) -> bool {
27 !matches!(self, Self::ReceivedTooEarly { .. })
28 }
29}
30
31pub fn validate_block_timing(
32 block: &ArcBlockWithHash,
33 genesis: &ArcBlockWithHash,
34 cur_global_slot: u32,
35 allow_block_too_late: bool,
36) -> Result<(), BlockPrevalidationError> {
37 let block_global_slot = block.global_slot();
38 let delta = genesis.constants().delta.as_u32();
39
40 if cur_global_slot < block_global_slot {
41 return Err(BlockPrevalidationError::ReceivedTooEarly {
42 current_global_slot: cur_global_slot,
43 block_global_slot,
44 });
45 } else if !allow_block_too_late && cur_global_slot.saturating_sub(block_global_slot) > delta {
46 return Err(BlockPrevalidationError::ReceivedTooLate {
47 current_global_slot: cur_global_slot,
48 block_global_slot,
49 delta,
50 });
51 }
52
53 Ok(())
54}
55
56pub fn validate_genesis_state(
57 block: &ArcBlockWithHash,
58 genesis: &ArcBlockWithHash,
59) -> Result<(), BlockPrevalidationError> {
60 if block.header().genesis_state_hash() != genesis.hash() {
61 return Err(BlockPrevalidationError::InvalidGenesisProtocolState);
62 }
63 Ok(())
64}
65
66pub fn validate_protocol_versions(block: &ArcBlockWithHash) -> Result<(), BlockPrevalidationError> {
67 let min_transaction_version = 1.into();
68 let v = &block.header().current_protocol_version;
69 let nv = block
70 .header()
71 .proposed_protocol_version_opt
72 .as_ref()
73 .unwrap_or(v);
74
75 let valid =
78 v.transaction >= min_transaction_version && nv.transaction >= min_transaction_version;
79 if !valid {
80 return Err(BlockPrevalidationError::InvalidProtocolVersion);
81 }
82
83 let compatible =
84 v.transaction == PROTOCOL_VERSION.transaction && v.network == PROTOCOL_VERSION.network;
85 if !compatible {
86 return Err(BlockPrevalidationError::MismatchedProtocolVersion);
87 }
88
89 Ok(())
90}
91
92pub fn validate_constants(
93 block: &ArcBlockWithHash,
94 genesis: &ArcBlockWithHash,
95) -> Result<(), BlockPrevalidationError> {
96 if block.constants() != genesis.constants() {
99 return Err(BlockPrevalidationError::ConsantsMismatch);
100 }
101 Ok(())
102}
103
104pub fn prevalidate_block(
105 block: &ArcBlockWithHash,
106 genesis: &ArcBlockWithHash,
107 cur_global_slot: u32,
108 allow_block_too_late: bool,
109) -> Result<(), BlockPrevalidationError> {
110 validate_block_timing(block, genesis, cur_global_slot, allow_block_too_late)?;
111 validate_genesis_state(block, genesis)?;
112 validate_protocol_versions(block)?;
113 validate_constants(block, genesis)?;
114
115 Ok(())
120}