node/block_producer_effectful/
block_producer_effectful_effects.rs1use crate::{
2 block_producer::BlockProducerCurrentState,
3 ledger::write::{LedgerWriteAction, LedgerWriteRequest},
4 BlockProducerAction, Store,
5};
6use mina_p2p_messages::v2::{
7 BlockchainSnarkBlockchainStableV2, ConsensusStakeProofStableV2,
8 MinaStateSnarkTransitionValueStableV2, ProverExtendBlockchainInputStableV2,
9};
10use openmina_node_account::AccountSecretKey;
11use redux::ActionWithMeta;
12
13use super::BlockProducerEffectfulAction;
14
15pub fn block_producer_effects<S: crate::Service>(
16 store: &mut Store<S>,
17 action: ActionWithMeta<BlockProducerEffectfulAction>,
18) {
19 let (action, meta) = action.split();
20
21 match action {
22 BlockProducerEffectfulAction::VrfEvaluator(a) => {
23 a.effects(&meta, store);
24 }
25 BlockProducerEffectfulAction::WonSlot { won_slot } => {
26 if let Some(stats) = store.service.stats() {
27 stats.block_producer().scheduled(meta.time(), &won_slot);
28 }
29 if !store.dispatch(BlockProducerAction::WonSlotWait) {
30 store.dispatch(BlockProducerAction::WonSlotProduceInit);
31 }
32 }
33 BlockProducerEffectfulAction::StagedLedgerDiffCreateInit => {
34 if let Some(stats) = store.service.stats() {
35 stats
36 .block_producer()
37 .staged_ledger_diff_create_start(meta.time());
38 }
39 let state = store.state.get();
40 let Some((won_slot, pred_block, producer, coinbase_receiver)) = None.or_else(|| {
41 let pred_block = state.block_producer.current_parent_chain()?.last()?;
42 let won_slot = state.block_producer.current_won_slot()?;
43 let config = state.block_producer.config()?;
44 Some((
45 won_slot,
46 pred_block,
47 &config.pub_key,
48 config.coinbase_receiver(),
49 ))
50 }) else {
51 return;
52 };
53
54 let completed_snarks = state
55 .snark_pool
56 .completed_snarks_iter()
57 .map(|snark| (snark.job_id(), snark.clone()))
58 .collect();
59 let supercharge_coinbase = true;
61 let is_new_epoch = won_slot.epoch()
64 > pred_block
65 .header()
66 .protocol_state
67 .body
68 .consensus_state
69 .epoch_count
70 .as_u32();
71
72 let transactions_by_fee = state.block_producer.pending_transactions();
73
74 store.dispatch(LedgerWriteAction::Init {
75 request: LedgerWriteRequest::StagedLedgerDiffCreate {
76 pred_block: pred_block.clone(),
77 global_slot_since_genesis: won_slot
78 .global_slot_since_genesis(pred_block.global_slot_diff()),
79 is_new_epoch,
80 producer: producer.clone(),
81 delegator: won_slot.delegator.0.clone(),
82 coinbase_receiver: coinbase_receiver.clone(),
83 completed_snarks,
84 supercharge_coinbase,
85 transactions_by_fee,
86 },
87 on_init: redux::callback!(
88 on_staged_ledger_diff_create_init(_request: LedgerWriteRequest) -> crate::Action {
89 BlockProducerAction::StagedLedgerDiffCreatePending
90 }
91 ),
92 });
93 }
94 BlockProducerEffectfulAction::StagedLedgerDiffCreateSuccess => {
95 if let Some(stats) = store.service.stats() {
96 stats
97 .block_producer()
98 .staged_ledger_diff_create_end(meta.time());
99 }
100 store.dispatch(BlockProducerAction::BlockUnprovenBuild);
101 }
102 BlockProducerEffectfulAction::BlockUnprovenBuild => {
103 if let Some(stats) = store.service.stats() {
104 let bp = &store.state.get().block_producer;
105 if let Some((block_hash, block, just_emitted_ledger_proof)) =
106 bp.with(None, |bp| match &bp.current {
107 BlockProducerCurrentState::BlockUnprovenBuilt {
108 block,
109 block_hash,
110 emitted_ledger_proof,
111 ..
112 } => Some((block_hash, block, emitted_ledger_proof.is_some())),
113 _ => None,
114 })
115 {
116 let ps = &block.protocol_state;
117 let cs = &ps.body.consensus_state;
118 let previous_state_hash = ps.previous_state_hash.to_string();
119 let state_hash = block_hash.to_string();
120 let global_slot_since_genesis = cs.global_slot_since_genesis.as_u32();
121 let height = cs.blockchain_length.as_u32();
122 openmina_core::info!(
123 meta.time();
124 message = "Unproven block built",
125 state_hash = state_hash,
126 previous_state_hash = previous_state_hash,
127 global_slot_since_genesis = global_slot_since_genesis,
128 height = height,
129 just_emitted_ledger_proof = just_emitted_ledger_proof,
130 );
131
132 stats
133 .block_producer()
134 .produced(meta.time(), block_hash, block);
135 }
136 }
137
138 store.dispatch(BlockProducerAction::BlockProveInit);
139 }
140 BlockProducerEffectfulAction::BlockProveInit => {
141 let service = &mut store.service;
142
143 if let Some(stats) = service.stats() {
144 stats.block_producer().proof_create_start(meta.time());
145 }
146 let Some((block_hash, input)) = store.state.get().block_producer.with(None, |bp| {
147 let BlockProducerCurrentState::BlockUnprovenBuilt {
148 won_slot,
149 chain,
150 emitted_ledger_proof,
151 pending_coinbase_update,
152 pending_coinbase_witness,
153 stake_proof_sparse_ledger,
154 block,
155 block_hash,
156 ..
157 } = &bp.current
158 else {
159 return None;
160 };
161
162 let pred_block = chain.last()?;
163
164 let producer_public_key = block
165 .protocol_state
166 .body
167 .consensus_state
168 .block_creator
169 .clone();
170
171 let input = Box::new(ProverExtendBlockchainInputStableV2 {
172 chain: BlockchainSnarkBlockchainStableV2 {
173 state: pred_block.header().protocol_state.clone(),
174 proof: pred_block.header().protocol_state_proof.clone(),
175 },
176 next_state: block.protocol_state.clone(),
177 block: MinaStateSnarkTransitionValueStableV2 {
178 blockchain_state: block.protocol_state.body.blockchain_state.clone(),
179 consensus_transition: block
180 .protocol_state
181 .body
182 .consensus_state
183 .curr_global_slot_since_hard_fork
184 .slot_number
185 .clone(),
186 pending_coinbase_update: pending_coinbase_update.clone(),
187 },
188 ledger_proof: emitted_ledger_proof.clone(),
189 prover_state: ConsensusStakeProofStableV2 {
190 delegator: won_slot.delegator.1.into(),
191 delegator_pk: won_slot.delegator.0.clone(),
192 coinbase_receiver_pk: block
193 .protocol_state
194 .body
195 .consensus_state
196 .coinbase_receiver
197 .clone(),
198 ledger: stake_proof_sparse_ledger.clone(),
199 producer_private_key: AccountSecretKey::genesis_producer().into(),
201 producer_public_key,
202 },
203 pending_coinbase: pending_coinbase_witness.clone(),
204 });
205 Some((block_hash.clone(), input))
206 }) else {
207 return;
208 };
209 service.prove(block_hash, input);
210 store.dispatch(BlockProducerAction::BlockProvePending);
211 }
212 BlockProducerEffectfulAction::BlockProveSuccess => {
213 if let Some(stats) = store.service.stats() {
214 stats.block_producer().proof_create_end(meta.time());
215 }
216 store.dispatch(BlockProducerAction::BlockProduced);
217 }
218 BlockProducerEffectfulAction::WonSlotDiscard { reason } => {
219 if let Some(stats) = store.service.stats() {
220 stats.block_producer().discarded(meta.time(), reason);
221 }
222 store.dispatch(BlockProducerAction::WonSlotSearch);
223 }
224 BlockProducerEffectfulAction::BlockProduced { block } => {
225 if let Some(stats) = store.service.stats() {
226 stats.block_producer().last_produced_block = Some(block.clone());
227 }
228 }
229 }
230}