mina_node/transition_frontier/genesis/
transition_frontier_genesis_reducer.rs

1use crate::{
2    account::AccountSecretKey, block_producer::calc_epoch_seed, p2p::P2pInitializeAction,
3    transition_frontier::genesis_effectful::TransitionFrontierGenesisEffectfulAction,
4};
5use ledger::{
6    dummy::dummy_blockchain_proof, scan_state::transaction_logic::local_state::LocalState,
7};
8use mina_core::{
9    block::{genesis::genesis_and_negative_one_protocol_states, BlockWithHash},
10    constants::PROTOCOL_VERSION,
11    error,
12};
13use mina_p2p_messages::v2;
14
15use super::{
16    empty_block_body, empty_block_body_hash, empty_pending_coinbase, empty_pending_coinbase_hash,
17    TransitionFrontierGenesisAction, TransitionFrontierGenesisActionWithMetaRef,
18    TransitionFrontierGenesisState,
19};
20
21impl TransitionFrontierGenesisState {
22    pub fn reducer(
23        mut state_context: crate::Substate<Self>,
24        action: TransitionFrontierGenesisActionWithMetaRef<'_>,
25    ) {
26        let Ok(state) = state_context.get_substate_mut() else {
27            // TODO: log or propagate
28            return;
29        };
30        let (action, meta) = action.split();
31
32        match action {
33            TransitionFrontierGenesisAction::LedgerLoadInit => {
34                let (dispatcher, global_state) = state_context.into_dispatcher_and_state();
35                let config = global_state.transition_frontier.config.genesis.clone();
36
37                dispatcher.push(TransitionFrontierGenesisAction::LedgerLoadPending);
38                dispatcher
39                    .push(TransitionFrontierGenesisEffectfulAction::LedgerLoadInit { config });
40            }
41            TransitionFrontierGenesisAction::LedgerLoadPending => {
42                *state = Self::LedgerLoadPending { time: meta.time() };
43            }
44            TransitionFrontierGenesisAction::LedgerLoadSuccess { data } => {
45                *state = Self::LedgerLoadSuccess {
46                    time: meta.time(),
47                    data: *data.clone(),
48                };
49
50                // Dispatch
51                let dispatcher = state_context.into_dispatcher();
52                // TODO(refactor): before this is dispatched genesis inject must be dispatched
53                dispatcher.push(TransitionFrontierGenesisAction::Produce);
54            }
55            TransitionFrontierGenesisAction::Produce => {
56                let Self::LedgerLoadSuccess { data, .. } = state else {
57                    return;
58                };
59
60                let genesis_vrf = ::mina_vrf::genesis_vrf(data.staking_epoch_seed.clone()).unwrap();
61                let genesis_vrf_hash = genesis_vrf.hash();
62
63                let Ok((negative_one, genesis, genesis_hash)) =
64                    genesis_and_negative_one_protocol_states(
65                        data.constants.clone(),
66                        data.genesis_ledger_hash.clone(),
67                        data.genesis_total_currency.clone(),
68                        data.staking_epoch_ledger_hash.clone(),
69                        data.staking_epoch_total_currency.clone(),
70                        data.next_epoch_ledger_hash.clone(),
71                        data.next_epoch_total_currency.clone(),
72                        AccountSecretKey::genesis_producer().public_key().into(),
73                        empty_pending_coinbase_hash(),
74                        (&LocalState::dummy()).into(),
75                        empty_block_body_hash(),
76                        genesis_vrf.into(),
77                        data.staking_epoch_seed.clone(),
78                        data.next_epoch_seed.clone(),
79                        calc_epoch_seed(&data.next_epoch_seed, genesis_vrf_hash), //data.next_epoch_seed.clone(),
80                    )
81                else {
82                    error!(meta.time(); "invalid negative protocol state");
83                    return;
84                };
85
86                *state = Self::Produced {
87                    time: meta.time(),
88                    negative_one,
89                    genesis,
90                    genesis_hash,
91                    genesis_producer_stake_proof: data.genesis_producer_stake_proof.clone(),
92                };
93
94                // Dispatch
95                let (dispatcher, global_state) = state_context.into_dispatcher_and_state();
96                if global_state.p2p.ready().is_none() {
97                    let TransitionFrontierGenesisState::Produced {
98                        genesis,
99                        genesis_hash,
100                        ..
101                    } = &global_state.transition_frontier.genesis
102                    else {
103                        error!(meta.time(); "incorrect state: {:?}", global_state.transition_frontier.genesis);
104                        return;
105                    };
106                    use mina_core::{constants, ChainId};
107                    let constraint_system_digests =
108                        mina_core::NetworkConfig::global().constraint_system_digests;
109                    let chain_id = ChainId::compute(
110                        constraint_system_digests,
111                        genesis_hash,
112                        &genesis.body.constants,
113                        constants::PROTOCOL_TRANSACTION_VERSION,
114                        constants::PROTOCOL_NETWORK_VERSION,
115                        &v2::UnsignedExtendedUInt32StableV1::from(constants::TX_POOL_MAX_SIZE),
116                    );
117                    dispatcher.push(P2pInitializeAction::Initialize { chain_id });
118                }
119                dispatcher.push(TransitionFrontierGenesisAction::ProveInit);
120            }
121            TransitionFrontierGenesisAction::ProveInit => {
122                let TransitionFrontierGenesisState::Produced {
123                    negative_one,
124                    genesis,
125                    genesis_hash,
126                    genesis_producer_stake_proof,
127                    ..
128                } = state
129                else {
130                    return;
131                };
132
133                let genesis_hash = genesis_hash.clone();
134                let producer_pk = genesis.body.consensus_state.block_creator.clone();
135                let delegator_pk = genesis.body.consensus_state.block_stake_winner.clone();
136
137                let input = v2::ProverExtendBlockchainInputStableV2 {
138                    chain: v2::BlockchainSnarkBlockchainStableV2 {
139                        state: negative_one.clone(),
140                        proof: dummy_blockchain_proof().clone(),
141                    },
142                    next_state: genesis.clone(),
143                    block: v2::MinaStateSnarkTransitionValueStableV2 {
144                        blockchain_state: genesis.body.blockchain_state.clone(),
145                        consensus_transition: genesis
146                            .body
147                            .consensus_state
148                            .curr_global_slot_since_hard_fork
149                            .slot_number
150                            .clone(),
151                        pending_coinbase_update: v2::MinaBasePendingCoinbaseUpdateStableV1::zero(),
152                    },
153                    ledger_proof: None,
154                    prover_state: v2::ConsensusStakeProofStableV2 {
155                        delegator: v2::MinaBaseAccountIndexStableV1(0u64.into()),
156                        delegator_pk,
157                        coinbase_receiver_pk: genesis
158                            .body
159                            .consensus_state
160                            .coinbase_receiver
161                            .clone(),
162                        producer_public_key: producer_pk,
163                        producer_private_key: AccountSecretKey::genesis_producer().into(),
164                        ledger: genesis_producer_stake_proof.clone(),
165                    },
166                    pending_coinbase: v2::MinaBasePendingCoinbaseWitnessStableV2 {
167                        pending_coinbases: (&empty_pending_coinbase()).into(),
168                        is_new_stack: true,
169                    },
170                };
171
172                // Dispatch
173                let dispatcher = state_context.into_dispatcher();
174
175                dispatcher.push(TransitionFrontierGenesisAction::ProvePending);
176                dispatcher.push(TransitionFrontierGenesisEffectfulAction::ProveInit {
177                    block_hash: genesis_hash,
178                    input: input.into(),
179                });
180            }
181            TransitionFrontierGenesisAction::ProvePending => {
182                let Self::Produced {
183                    negative_one,
184                    genesis,
185                    genesis_hash,
186                    genesis_producer_stake_proof,
187                    ..
188                } = state
189                else {
190                    return;
191                };
192
193                *state = Self::ProvePending {
194                    time: meta.time(),
195                    negative_one: negative_one.clone(),
196                    genesis: genesis.clone(),
197                    genesis_hash: genesis_hash.clone(),
198                    genesis_producer_stake_proof: genesis_producer_stake_proof.clone(),
199                };
200            }
201            TransitionFrontierGenesisAction::ProveSuccess { proof } => {
202                let Self::ProvePending {
203                    genesis,
204                    genesis_hash,
205                    ..
206                } = state
207                else {
208                    return;
209                };
210
211                let block = v2::MinaBlockBlockStableV2 {
212                    header: v2::MinaBlockHeaderStableV2 {
213                        protocol_state: genesis.clone(),
214                        protocol_state_proof: proof.clone(),
215                        delta_block_chain_proof: (
216                            genesis_hash.clone(),
217                            std::iter::empty().collect(),
218                        ),
219                        current_protocol_version: PROTOCOL_VERSION.clone(),
220                        proposed_protocol_version_opt: None,
221                    },
222                    body: v2::StagedLedgerDiffBodyStableV1 {
223                        staged_ledger_diff: empty_block_body(),
224                    },
225                };
226
227                let Ok(genesis) = BlockWithHash::try_new(block.into()) else {
228                    error!(meta.time(); "invalid `genesis` block");
229                    return;
230                };
231
232                *state = Self::ProveSuccess {
233                    time: meta.time(),
234                    genesis,
235                };
236            }
237        }
238    }
239}