Skip to content

Commit 463cc59

Browse files
authored
Merge pull request #1083 from openmina/feat/heartbeats-block-proof
feat(heartbeats): Verify block proofs
2 parents 2f10d9a + fdf4ad0 commit 463cc59

13 files changed

+318
-156
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/block/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub use block_with_hash::{BlockHeaderWithHash, BlockWithHash};
44
mod applied_block;
55
pub use applied_block::AppliedBlock;
66

7+
pub mod prevalidate;
8+
79
pub mod genesis;
810

911
use std::sync::Arc;

core/src/block/prevalidate.rs

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

node/src/p2p/callbacks/p2p_callbacks_reducer.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ use mina_p2p_messages::{
33
gossip::GossipNetMessageV2,
44
v2::{MinaLedgerSyncLedgerAnswerStableV2, StateHash},
55
};
6-
use openmina_core::{block::BlockWithHash, bug_condition, log, transaction::TransactionWithHash};
6+
use openmina_core::{
7+
block::{prevalidate::BlockPrevalidationError, BlockWithHash},
8+
bug_condition, log,
9+
transaction::TransactionWithHash,
10+
};
711
use p2p::{
812
channels::{
913
best_tip::P2pChannelsBestTipAction,
@@ -18,7 +22,6 @@ use redux::{ActionMeta, ActionWithMeta, Dispatcher};
1822
use crate::{
1923
p2p_ready,
2024
snark_pool::candidate::SnarkPoolCandidateAction,
21-
state::BlockPrevalidationError,
2225
transaction_pool::candidate::TransactionPoolCandidateAction,
2326
transition_frontier::candidate::{allow_block_too_late, TransitionFrontierCandidateAction},
2427
transition_frontier::sync::{

node/src/state.rs

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33

44
use malloc_size_of_derive::MallocSizeOf;
55
use mina_p2p_messages::v2;
6-
use openmina_core::constants::PROTOCOL_VERSION;
6+
use openmina_core::block::prevalidate::{prevalidate_block, BlockPrevalidationError};
77
use openmina_core::transaction::{TransactionInfo, TransactionWithHash};
88
use p2p::P2pNetworkPubsubMessageCacheId;
99
use rand::prelude::*;
@@ -80,25 +80,6 @@ pub struct State {
8080
applied_actions_count: u64,
8181
}
8282

83-
#[derive(Serialize, Deserialize, Debug, Clone)]
84-
pub enum BlockPrevalidationError {
85-
GenesisNotReady,
86-
ReceivedTooEarly {
87-
current_global_slot: u32,
88-
block_global_slot: u32,
89-
},
90-
ReceivedTooLate {
91-
current_global_slot: u32,
92-
block_global_slot: u32,
93-
delta: u32,
94-
},
95-
InvalidGenesisProtocolState,
96-
InvalidProtocolVersion,
97-
MismatchedProtocolVersion,
98-
ConsantsMismatch,
99-
InvalidDeltaBlockChainProof,
100-
}
101-
10283
// Substate accessors that will be used in reducers
10384
use openmina_core::{bug_condition, impl_substate_access, SubstateAccess};
10485

@@ -408,70 +389,7 @@ impl State {
408389
return Err(BlockPrevalidationError::GenesisNotReady);
409390
};
410391

411-
// received_at_valid_time
412-
// https://github.com/minaprotocol/mina/blob/6af211ad58e9356f00ea4a636cea70aa8267c072/src/lib/consensus/proof_of_stake.ml#L2746
413-
{
414-
let block_global_slot = block.global_slot();
415-
416-
let delta = genesis.constants().delta.as_u32();
417-
if cur_global_slot < block_global_slot {
418-
// Too_early
419-
return Err(BlockPrevalidationError::ReceivedTooEarly {
420-
current_global_slot: cur_global_slot,
421-
block_global_slot,
422-
});
423-
} else if !allow_block_too_late
424-
&& cur_global_slot.saturating_sub(block_global_slot) > delta
425-
{
426-
// Too_late
427-
return Err(BlockPrevalidationError::ReceivedTooLate {
428-
current_global_slot: cur_global_slot,
429-
block_global_slot,
430-
delta,
431-
});
432-
}
433-
}
434-
435-
if block.header().genesis_state_hash() != genesis.hash() {
436-
return Err(BlockPrevalidationError::InvalidGenesisProtocolState);
437-
}
438-
439-
let (protocol_versions_are_valid, protocol_version_matches_daemon) = {
440-
let min_transaction_version = 1.into();
441-
let v = &block.header().current_protocol_version;
442-
let nv = block
443-
.header()
444-
.proposed_protocol_version_opt
445-
.as_ref()
446-
.unwrap_or(v);
447-
448-
// Our version values are unsigned, so there is no need to check that the
449-
// other parts are not negative.
450-
let valid = v.transaction >= min_transaction_version
451-
&& nv.transaction >= min_transaction_version;
452-
let compatible = v.transaction == PROTOCOL_VERSION.transaction
453-
&& v.network == PROTOCOL_VERSION.network;
454-
455-
(valid, compatible)
456-
};
457-
458-
if !protocol_versions_are_valid {
459-
return Err(BlockPrevalidationError::InvalidProtocolVersion);
460-
} else if !protocol_version_matches_daemon {
461-
return Err(BlockPrevalidationError::MismatchedProtocolVersion);
462-
}
463-
464-
// NOTE: currently these cannot change between blocks, but that
465-
// may not always be true?
466-
if block.constants() != genesis.constants() {
467-
return Err(BlockPrevalidationError::ConsantsMismatch);
468-
}
469-
470-
// TODO(tizoc): check for InvalidDeltaBlockChainProof
471-
// https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/mina_block/validation.ml#L369
472-
// https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/transition_chain_verifier/transition_chain_verifier.ml
473-
474-
Ok(())
392+
prevalidate_block(block, &genesis, cur_global_slot, allow_block_too_late)
475393
}
476394

477395
pub fn should_log_node_id(&self) -> bool {

node/src/transition_frontier/candidate/transition_frontier_candidate_actions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::sync::Arc;
22

33
use mina_p2p_messages::v2::{MinaBlockBlockStableV2, StateHash};
4+
use openmina_core::block::prevalidate::BlockPrevalidationError;
45
use openmina_core::block::{ArcBlockWithHash, BlockWithHash};
56
use openmina_core::consensus::consensus_take;
67
use openmina_core::{action_event, ActionEvent};
78
use serde::{Deserialize, Serialize};
89
use snark::block_verify::SnarkBlockVerifyError;
910

1011
use crate::snark::block_verify::SnarkBlockVerifyId;
11-
use crate::state::BlockPrevalidationError;
1212

1313
use super::TransitionFrontierCandidateStatus;
1414

tools/heartbeats-processor/.sqlx/query-489059c80fd17d3c1687d5e301fc85a4691c66707c673886ae08077a9e80c0e1.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/heartbeats-processor/.sqlx/query-94669ea962673f9d266e0cbeeaf854c789c92aa5ccc2673293022c7b505243e8.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

tools/heartbeats-processor/.sqlx/query-ad9dff13f32bd4e8193be71bd22a2e52c496fceabbd9a2a916f610fb7ed27a32.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/heartbeats-processor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ dotenv = "0.15"
1515
clap = { version = "4.4", features = ["derive"] }
1616
gcloud-sdk = { version = "0.26.0", default-features = false, features = ["google-firestore-v1"] }
1717
base64 = "0.22"
18+
mina-tree = { path = "../../ledger" }
19+
snark = { path = "../../snark" }
1820

1921
mina-p2p-messages = { workspace = true }
2022
openmina-core = { path = "../../core" }

0 commit comments

Comments
 (0)