Skip to content

Commit 5c85b24

Browse files
authored
Merge pull request #1090 from openmina/feat/consensus/do_consensus_first_then_verification
Transition Frontier: do cheap consensus first then expensive verification
2 parents 9cccc4e + e00e528 commit 5c85b24

File tree

8 files changed

+281
-496
lines changed

8 files changed

+281
-496
lines changed

node/src/action_kind.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -618,19 +618,15 @@ pub enum ActionKind {
618618
TransitionFrontierGenesisProvenInject,
619619
TransitionFrontierSyncFailed,
620620
TransitionFrontierSynced,
621-
TransitionFrontierCandidateBestTipUpdate,
622621
TransitionFrontierCandidateBlockChainProofUpdate,
623622
TransitionFrontierCandidateBlockPrevalidateError,
624623
TransitionFrontierCandidateBlockPrevalidateSuccess,
625624
TransitionFrontierCandidateBlockReceived,
626625
TransitionFrontierCandidateBlockSnarkVerifyError,
627626
TransitionFrontierCandidateBlockSnarkVerifyPending,
628627
TransitionFrontierCandidateBlockSnarkVerifySuccess,
629-
TransitionFrontierCandidateDetectForkRange,
630-
TransitionFrontierCandidateLongRangeForkResolve,
631628
TransitionFrontierCandidateP2pBestTipUpdate,
632629
TransitionFrontierCandidatePrune,
633-
TransitionFrontierCandidateShortRangeForkResolve,
634630
TransitionFrontierCandidateTransitionFrontierSyncTargetUpdate,
635631
TransitionFrontierGenesisLedgerLoadInit,
636632
TransitionFrontierGenesisLedgerLoadPending,
@@ -720,7 +716,7 @@ pub enum ActionKind {
720716
}
721717

722718
impl ActionKind {
723-
pub const COUNT: u16 = 610;
719+
pub const COUNT: u16 = 606;
724720
}
725721

726722
impl std::fmt::Display for ActionKind {
@@ -1434,6 +1430,9 @@ impl ActionKindGet for TransitionFrontierGenesisEffectfulAction {
14341430
impl ActionKindGet for TransitionFrontierCandidateAction {
14351431
fn kind(&self) -> ActionKind {
14361432
match self {
1433+
Self::P2pBestTipUpdate { .. } => {
1434+
ActionKind::TransitionFrontierCandidateP2pBestTipUpdate
1435+
}
14371436
Self::BlockReceived { .. } => ActionKind::TransitionFrontierCandidateBlockReceived,
14381437
Self::BlockPrevalidateSuccess { .. } => {
14391438
ActionKind::TransitionFrontierCandidateBlockPrevalidateSuccess
@@ -1453,20 +1452,9 @@ impl ActionKindGet for TransitionFrontierCandidateAction {
14531452
Self::BlockSnarkVerifyError { .. } => {
14541453
ActionKind::TransitionFrontierCandidateBlockSnarkVerifyError
14551454
}
1456-
Self::DetectForkRange { .. } => ActionKind::TransitionFrontierCandidateDetectForkRange,
1457-
Self::ShortRangeForkResolve { .. } => {
1458-
ActionKind::TransitionFrontierCandidateShortRangeForkResolve
1459-
}
1460-
Self::LongRangeForkResolve { .. } => {
1461-
ActionKind::TransitionFrontierCandidateLongRangeForkResolve
1462-
}
1463-
Self::BestTipUpdate { .. } => ActionKind::TransitionFrontierCandidateBestTipUpdate,
14641455
Self::TransitionFrontierSyncTargetUpdate => {
14651456
ActionKind::TransitionFrontierCandidateTransitionFrontierSyncTargetUpdate
14661457
}
1467-
Self::P2pBestTipUpdate { .. } => {
1468-
ActionKind::TransitionFrontierCandidateP2pBestTipUpdate
1469-
}
14701458
Self::Prune => ActionKind::TransitionFrontierCandidatePrune,
14711459
}
14721460
}

node/src/effects.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,17 @@ pub fn effects<S: Service>(store: &mut Store<S>, action: ActionWithMeta) {
113113
fn p2p_request_best_tip_if_needed<S: Service>(store: &mut Store<S>) {
114114
// TODO(binier): refactor
115115
let state = store.state();
116-
let consensus_best_tip_hash = state.transition_frontier.candidates.best_tip.as_ref();
116+
let best_candidate = state.transition_frontier.candidates.best_verified();
117+
let best_candidate_hash = best_candidate.map(|s| s.block.hash());
117118
let best_tip_hash = state.transition_frontier.best_tip().map(|v| &v.hash);
118119
let syncing_best_tip_hash = state.transition_frontier.sync.best_tip().map(|v| &v.hash);
119120

120-
if consensus_best_tip_hash.is_some()
121-
&& consensus_best_tip_hash != best_tip_hash
122-
&& consensus_best_tip_hash != syncing_best_tip_hash
123-
&& state
124-
.transition_frontier
125-
.candidates
126-
.best_tip_chain_proof
127-
.is_none()
121+
if best_candidate.is_some()
122+
&& best_candidate_hash != best_tip_hash
123+
&& best_candidate_hash != syncing_best_tip_hash
124+
&& best_candidate.is_some_and(|s| s.chain_proof.is_none())
128125
{
129-
request_best_tip(store, consensus_best_tip_hash.cloned());
126+
request_best_tip(store, best_candidate_hash.cloned());
130127
}
131128
}
132129
use mina_p2p_messages::v2::StateHash;

node/src/logger/logger_effects.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::p2p::connection::P2pConnectionAction;
99
use crate::p2p::network::P2pNetworkAction;
1010
use crate::p2p::P2pAction;
1111
use crate::snark::SnarkAction;
12+
use crate::transition_frontier::candidate::TransitionFrontierCandidateAction;
1213
use crate::{
1314
Action, ActionWithMetaRef, BlockProducerAction, Service, Store, TransitionFrontierAction,
1415
};
@@ -119,6 +120,18 @@ pub fn logger_effects<S: Service>(store: &Store<S>, action: ActionWithMetaRef<'_
119120
Action::Snark(SnarkAction::WorkVerify(a)) => a.action_event(&context),
120121
Action::Snark(SnarkAction::UserCommandVerify(a)) => a.action_event(&context),
121122
Action::TransitionFrontier(a) => match a {
123+
TransitionFrontierAction::Candidate(
124+
TransitionFrontierCandidateAction::BlockReceived { block, chain_proof },
125+
) => {
126+
openmina_core::action_info!(
127+
context,
128+
kind = action.kind().to_string(),
129+
summary = "candidate block received",
130+
block_hash = block.hash().to_string(),
131+
block_height = block.height(),
132+
has_chain_proof = chain_proof.is_some(),
133+
);
134+
}
122135
TransitionFrontierAction::Synced { .. } => {
123136
let tip = store.state().transition_frontier.best_tip().unwrap();
124137

node/src/transition_frontier/candidate/transition_frontier_candidate_actions.rs

Lines changed: 48 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
use std::sync::Arc;
2-
3-
use mina_p2p_messages::v2::{MinaBlockBlockStableV2, StateHash};
1+
use mina_p2p_messages::v2::StateHash;
42
use openmina_core::block::prevalidate::BlockPrevalidationError;
5-
use openmina_core::block::{ArcBlockWithHash, BlockWithHash};
3+
use openmina_core::block::ArcBlockWithHash;
64
use openmina_core::consensus::consensus_take;
75
use openmina_core::{action_event, ActionEvent};
86
use serde::{Deserialize, Serialize};
97
use snark::block_verify::SnarkBlockVerifyError;
108

119
use crate::snark::block_verify::SnarkBlockVerifyId;
1210

13-
use super::TransitionFrontierCandidateStatus;
14-
1511
pub type TransitionFrontierCandidateActionWithMeta =
1612
redux::ActionWithMeta<TransitionFrontierCandidateAction>;
1713
pub type TransitionFrontierCandidateActionWithMetaRef<'a> =
@@ -22,10 +18,11 @@ pub type TransitionFrontierCandidateActionWithMetaRef<'a> =
2218
#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)]
2319
#[action_event(level = debug, fields(debug(hash), debug(error)))]
2420
pub enum TransitionFrontierCandidateAction {
25-
#[action_event(level = info)]
21+
P2pBestTipUpdate {
22+
best_tip: ArcBlockWithHash,
23+
},
2624
BlockReceived {
27-
hash: StateHash,
28-
block: Arc<MinaBlockBlockStableV2>,
25+
block: ArcBlockWithHash,
2926
chain_proof: Option<(Vec<StateHash>, ArcBlockWithHash)>,
3027
},
3128
BlockPrevalidateSuccess {
@@ -52,131 +49,49 @@ pub enum TransitionFrontierCandidateAction {
5249
hash: StateHash,
5350
error: SnarkBlockVerifyError,
5451
},
55-
DetectForkRange {
56-
hash: StateHash,
57-
},
58-
ShortRangeForkResolve {
59-
hash: StateHash,
60-
},
61-
LongRangeForkResolve {
62-
hash: StateHash,
63-
},
64-
#[action_event(level = info)]
65-
BestTipUpdate {
66-
hash: StateHash,
67-
},
6852
TransitionFrontierSyncTargetUpdate,
69-
P2pBestTipUpdate {
70-
best_tip: BlockWithHash<Arc<MinaBlockBlockStableV2>>,
71-
},
7253
Prune,
7354
}
7455

7556
impl redux::EnablingCondition<crate::State> for TransitionFrontierCandidateAction {
7657
fn is_enabled(&self, state: &crate::State, _time: redux::Timestamp) -> bool {
7758
match self {
78-
TransitionFrontierCandidateAction::BlockReceived { hash, block, .. } => {
79-
let block = ArcBlockWithHash {
80-
hash: hash.clone(),
81-
block: block.clone()
82-
};
83-
!block.is_genesis() && !state.transition_frontier.candidates.blocks.contains_key(hash)
84-
},
59+
TransitionFrontierCandidateAction::P2pBestTipUpdate { .. } => true,
60+
TransitionFrontierCandidateAction::BlockReceived { block, .. } => {
61+
!block.is_genesis() && !state.transition_frontier.candidates.contains(block.hash())
62+
}
8563
TransitionFrontierCandidateAction::BlockPrevalidateSuccess { hash }
8664
| TransitionFrontierCandidateAction::BlockPrevalidateError { hash, .. } => state
87-
.transition_frontier.candidates
88-
.blocks
65+
.transition_frontier
66+
.candidates
8967
.get(hash)
9068
.is_some_and(|block| block.status.is_received()),
91-
TransitionFrontierCandidateAction::BlockChainProofUpdate { hash, .. } => {
92-
(state.transition_frontier.candidates.best_tip.as_ref() == Some(hash)
93-
&& state.transition_frontier.candidates.best_tip_chain_proof.is_none())
94-
|| state.transition_frontier
95-
.candidates
96-
.blocks
97-
.get(hash)
98-
.is_some_and( |b| b.status.is_pending() && b.chain_proof.is_none())
99-
},
69+
TransitionFrontierCandidateAction::BlockChainProofUpdate { hash, .. } => state
70+
.transition_frontier
71+
.candidates
72+
.is_chain_proof_needed(hash),
10073
TransitionFrontierCandidateAction::BlockSnarkVerifyPending { req_id, hash } => {
10174
state
10275
.transition_frontier
10376
.candidates
104-
.blocks
10577
.get(hash)
106-
.is_some_and( |block| block.status.is_prevalidated())
78+
.is_some_and(|block| block.status.is_prevalidated())
10779
&& state.snark.block_verify.jobs.contains(*req_id)
108-
},
109-
TransitionFrontierCandidateAction::BlockSnarkVerifySuccess { hash } => {
110-
state
111-
.transition_frontier
112-
.candidates
113-
.blocks
114-
.get(hash)
115-
.is_some_and( |block| block.status.is_snark_verify_pending())
116-
},
117-
TransitionFrontierCandidateAction::BlockSnarkVerifyError { hash, .. } => {
118-
state
119-
.transition_frontier
120-
.candidates
121-
.blocks
122-
.get(hash)
123-
.is_some_and( |block| block.status.is_snark_verify_pending())
124-
},
125-
TransitionFrontierCandidateAction::DetectForkRange { hash } => {
126-
state
127-
.transition_frontier
128-
.candidates
129-
.blocks
130-
.get(hash)
131-
.is_some_and( |block| {
132-
matches!(
133-
block.status,
134-
TransitionFrontierCandidateStatus::SnarkVerifySuccess { .. }
135-
)
136-
})
137-
},
138-
TransitionFrontierCandidateAction::ShortRangeForkResolve { hash } => {
139-
state
140-
.transition_frontier
141-
.candidates
142-
.blocks
143-
.get(hash)
144-
.is_some_and( |block| match state.transition_frontier.candidates.best_tip() {
145-
Some(tip) => {
146-
matches!(
147-
&block.status,
148-
TransitionFrontierCandidateStatus::ForkRangeDetected { compared_with, short_fork, .. }
149-
if compared_with.as_ref() == Some(tip.hash) && *short_fork
150-
)
151-
}
152-
None => true,
153-
})
154-
},
155-
TransitionFrontierCandidateAction::LongRangeForkResolve { hash } => {
156-
state
157-
.transition_frontier
158-
.candidates
159-
.blocks
160-
.get(hash)
161-
.is_some_and( |block| match state.transition_frontier.candidates.best_tip() {
162-
Some(tip) => {
163-
matches!(
164-
&block.status,
165-
TransitionFrontierCandidateStatus::ForkRangeDetected { compared_with, short_fork, .. }
166-
if compared_with.as_ref() == Some(tip.hash) && !*short_fork
167-
)
168-
}
169-
None => false,
170-
})
171-
},
172-
TransitionFrontierCandidateAction::BestTipUpdate { hash } => {
173-
state
174-
.transition_frontier
175-
.candidates
176-
.is_candidate_decided_to_use_as_tip(hash)
177-
},
80+
}
81+
TransitionFrontierCandidateAction::BlockSnarkVerifySuccess { hash } => state
82+
.transition_frontier
83+
.candidates
84+
.get(hash)
85+
.is_some_and(|block| block.status.is_snark_verify_pending()),
86+
TransitionFrontierCandidateAction::BlockSnarkVerifyError { hash, .. } => state
87+
.transition_frontier
88+
.candidates
89+
.get(hash)
90+
.is_some_and(|block| block.status.is_snark_verify_pending()),
17891
TransitionFrontierCandidateAction::TransitionFrontierSyncTargetUpdate => {
179-
let Some(best_tip) = state.transition_frontier.candidates.best_tip_block_with_hash() else {
92+
let Some(best_candidate) =
93+
state.transition_frontier.candidates.best_verified_block()
94+
else {
18095
return false;
18196
};
18297
// do not need to update transition frontier sync target.
@@ -185,18 +100,28 @@ impl redux::EnablingCondition<crate::State> for TransitionFrontierCandidateActio
185100
state.transition_frontier.sync.best_tip(),
186101
])
187102
.flatten()
188-
.any(|b| b.hash() == best_tip.hash()
189-
|| !consensus_take(b.consensus_state(), best_tip.consensus_state(), b.hash(), best_tip.hash())) {
103+
.any(|b| {
104+
b.hash() == best_candidate.hash()
105+
|| !consensus_take(
106+
b.consensus_state(),
107+
best_candidate.consensus_state(),
108+
b.hash(),
109+
best_candidate.hash(),
110+
)
111+
}) {
190112
return false;
191113
}
192114

193115
// has enough data
194-
state.transition_frontier.candidates.best_tip_chain_proof(&state.transition_frontier).is_some()
195-
},
196-
TransitionFrontierCandidateAction::P2pBestTipUpdate { .. } => true,
116+
state
117+
.transition_frontier
118+
.candidates
119+
.best_verified_block_chain_proof(&state.transition_frontier)
120+
.is_some()
121+
}
197122
TransitionFrontierCandidateAction::Prune => {
198-
state.transition_frontier.candidates.best_tip().is_some()
199-
},
123+
state.transition_frontier.candidates.best().is_some()
124+
}
200125
}
201126
}
202127
}

0 commit comments

Comments
 (0)