1use ark_ff::fields::arithmetic::InvalidBigInt;
2use mina_curves::pasta::Fp;
3use mina_p2p_messages::v2;
4
5use crate::scan_state::{
6 currency::{self, Length, Slot},
7 transaction_logic::protocol_state::{EpochData, EpochLedger},
8};
9
10use super::{
11 block::{
12 consensus::{CheckedConsensusState, ConsensusState},
13 ProtocolState, ProtocolStateBody,
14 },
15 numbers::{
16 currency::{CheckedAmount, CheckedCurrency},
17 nat::{CheckedLength, CheckedNat, CheckedSlot},
18 },
19};
20
21fn state_hash(value: Fp) -> v2::StateHash {
22 v2::DataHashLibStateHashStableV1(value.into()).into()
23}
24
25fn ledger_hash(value: Fp) -> v2::LedgerHash {
26 v2::MinaBaseLedgerHash0StableV1(value.into()).into()
27}
28
29fn epoch_ledger_seed(value: Fp) -> v2::EpochSeed {
30 v2::MinaBaseEpochSeedStableV1(value.into()).into()
31}
32
33impl From<CheckedLength<Fp>> for v2::UnsignedExtendedUInt32StableV1 {
34 fn from(value: CheckedLength<Fp>) -> Self {
35 Self(value.to_inner().as_u32().into())
36 }
37}
38
39impl From<CheckedSlot<Fp>> for v2::UnsignedExtendedUInt32StableV1 {
40 fn from(value: CheckedSlot<Fp>) -> Self {
41 Self(value.to_inner().as_u32().into())
42 }
43}
44
45impl From<CheckedAmount<Fp>> for v2::UnsignedExtendedUInt64Int64ForVersionTagsStableV1 {
46 fn from(value: CheckedAmount<Fp>) -> Self {
47 Self(value.to_inner().as_u64().into())
48 }
49}
50
51impl From<CheckedAmount<Fp>> for v2::CurrencyAmountStableV1 {
52 fn from(value: CheckedAmount<Fp>) -> Self {
53 Self(value.into())
54 }
55}
56
57impl From<&EpochLedger<Fp>> for v2::MinaBaseEpochLedgerValueStableV1 {
58 fn from(value: &EpochLedger<Fp>) -> Self {
59 Self {
60 hash: ledger_hash(value.hash),
61 total_currency: value.total_currency.into(),
62 }
63 }
64}
65
66impl From<&EpochData<Fp>>
67 for v2::ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1
68{
69 fn from(value: &EpochData<Fp>) -> Self {
70 Self {
71 ledger: (&value.ledger).into(),
72 seed: epoch_ledger_seed(value.seed),
73 start_checkpoint: state_hash(value.start_checkpoint),
74 lock_checkpoint: state_hash(value.lock_checkpoint),
75 epoch_length: (&value.epoch_length).into(),
76 }
77 }
78}
79
80impl From<&EpochData<Fp>>
81 for v2::ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1
82{
83 fn from(value: &EpochData<Fp>) -> Self {
84 Self {
85 ledger: (&value.ledger).into(),
86 seed: epoch_ledger_seed(value.seed),
87 start_checkpoint: state_hash(value.start_checkpoint),
88 lock_checkpoint: state_hash(value.lock_checkpoint),
89 epoch_length: (&value.epoch_length).into(),
90 }
91 }
92}
93
94impl From<&ProtocolState> for v2::MinaStateProtocolStateValueStableV2 {
95 fn from(value: &ProtocolState) -> Self {
96 Self {
97 previous_state_hash: state_hash(value.previous_state_hash),
98 body: (&value.body).into(),
99 }
100 }
101}
102
103impl TryFrom<&v2::MinaStateProtocolStateValueStableV2> for ProtocolState {
104 type Error = InvalidBigInt;
105
106 fn try_from(value: &v2::MinaStateProtocolStateValueStableV2) -> Result<Self, Self::Error> {
107 let v2::MinaStateProtocolStateValueStableV2 {
108 previous_state_hash,
109 body,
110 } = value;
111
112 Ok(Self {
113 previous_state_hash: previous_state_hash.to_field()?,
114 body: body.try_into()?,
115 })
116 }
117}
118
119impl From<&super::block::BlockchainState> for v2::MinaStateBlockchainStateValueStableV2 {
120 fn from(value: &super::block::BlockchainState) -> Self {
121 let super::block::BlockchainState {
122 staged_ledger_hash,
123 genesis_ledger_hash,
124 ledger_proof_statement,
125 timestamp,
126 body_reference,
127 } = value;
128
129 Self {
130 staged_ledger_hash: staged_ledger_hash.into(),
131 genesis_ledger_hash: genesis_ledger_hash.into(),
132 ledger_proof_statement: ledger_proof_statement.into(),
133 timestamp: timestamp.into(),
134 body_reference: body_reference.clone(),
135 }
136 }
137}
138
139impl From<&ProtocolStateBody<ConsensusState>> for v2::MinaStateProtocolStateBodyValueStableV2 {
140 fn from(value: &ProtocolStateBody) -> Self {
141 Self {
142 genesis_state_hash: state_hash(value.genesis_state_hash),
143 blockchain_state: (&value.blockchain_state).into(),
144 consensus_state: (&value.consensus_state).into(),
145 constants: value.constants.clone(),
146 }
147 }
148}
149
150impl TryFrom<&v2::MinaStateProtocolStateBodyValueStableV2> for ProtocolStateBody<ConsensusState> {
151 type Error = InvalidBigInt;
152
153 fn try_from(value: &v2::MinaStateProtocolStateBodyValueStableV2) -> Result<Self, Self::Error> {
154 let v2::MinaStateProtocolStateBodyValueStableV2 {
155 genesis_state_hash,
156 blockchain_state,
157 consensus_state,
158 constants,
159 } = value;
160
161 Ok(Self {
162 genesis_state_hash: genesis_state_hash.to_field()?,
163 blockchain_state: blockchain_state.try_into()?,
164 consensus_state: consensus_state.try_into()?,
165 constants: constants.clone(),
166 })
167 }
168}
169
170impl TryFrom<&v2::ConsensusProofOfStakeDataConsensusStateValueStableV2> for ConsensusState {
171 type Error = InvalidBigInt;
172
173 fn try_from(
174 value: &v2::ConsensusProofOfStakeDataConsensusStateValueStableV2,
175 ) -> Result<Self, Self::Error> {
176 let v2::ConsensusProofOfStakeDataConsensusStateValueStableV2 {
177 blockchain_length,
178 epoch_count,
179 min_window_density,
180 sub_window_densities,
181 last_vrf_output,
182 total_currency,
183 curr_global_slot_since_hard_fork,
184 global_slot_since_genesis,
185 staking_epoch_data,
186 next_epoch_data,
187 has_ancestor_in_same_checkpoint_window,
188 block_stake_winner,
189 block_creator,
190 coinbase_receiver,
191 supercharge_coinbase,
192 } = value;
193
194 Ok(Self {
195 blockchain_length: Length::from_u32(blockchain_length.as_u32()),
196 epoch_count: Length::from_u32(epoch_count.as_u32()),
197 min_window_density: Length::from_u32(min_window_density.as_u32()),
198 sub_window_densities: sub_window_densities
199 .iter()
200 .map(|sub| Length::from_u32(sub.as_u32()))
201 .collect(),
202 last_vrf_output: {
203 let mut output = Vec::with_capacity(253);
204 output.extend(last_vrf_output.iter().take(31).flat_map(|b| {
205 [1u8, 2, 4, 8, 16, 32, 64, 128]
206 .iter()
207 .map(|bit| *bit & *b != 0)
208 }));
209 let last_byte = last_vrf_output[31];
211 output.extend([1, 2, 4, 8, 16].iter().map(|bit| *bit & last_byte != 0));
212 output.try_into().map_err(|_| InvalidBigInt)? },
214 curr_global_slot_since_hard_fork: curr_global_slot_since_hard_fork.into(),
215 global_slot_since_genesis: Slot::from_u32(global_slot_since_genesis.as_u32()),
216 total_currency: currency::Amount::from_u64(total_currency.as_u64()),
217 staking_epoch_data: staking_epoch_data.try_into()?,
218 next_epoch_data: next_epoch_data.try_into()?,
219 has_ancestor_in_same_checkpoint_window: *has_ancestor_in_same_checkpoint_window,
220 block_stake_winner: block_stake_winner.try_into()?,
221 block_creator: block_creator.try_into()?,
222 coinbase_receiver: coinbase_receiver.try_into()?,
223 supercharge_coinbase: *supercharge_coinbase,
224 })
225 }
226}
227
228impl From<&CheckedConsensusState> for v2::ConsensusProofOfStakeDataConsensusStateValueStableV2 {
229 fn from(value: &CheckedConsensusState) -> Self {
230 Self {
231 blockchain_length: value.blockchain_length.into(),
232 epoch_count: value.epoch_count.into(),
233 min_window_density: value.min_window_density.into(),
234 sub_window_densities: value
235 .sub_window_densities
236 .iter()
237 .map(|v| (*v).into())
238 .collect(),
239 last_vrf_output: v2::ConsensusVrfOutputTruncatedStableV1(Vec::new().into()),
241 total_currency: value.total_currency.into(),
242 curr_global_slot_since_hard_fork: v2::ConsensusGlobalSlotStableV1 {
243 slot_number: v2::MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(
244 value.curr_global_slot_since_hard_fork.slot_number.into(),
245 ),
246 slots_per_epoch: value
247 .curr_global_slot_since_hard_fork
248 .slots_per_epoch
249 .into(),
250 },
251 global_slot_since_genesis: v2::MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
252 v2::UnsignedExtendedUInt32StableV1(
253 value.global_slot_since_genesis.to_inner().as_u32().into(),
254 ),
255 ),
256 staking_epoch_data: (&value.staking_epoch_data).into(),
257 next_epoch_data: (&value.next_epoch_data).into(),
258 has_ancestor_in_same_checkpoint_window: value
259 .has_ancestor_in_same_checkpoint_window
260 .as_bool(),
261 block_stake_winner: (&value.block_stake_winner).into(),
262 block_creator: (&value.block_creator).into(),
263 coinbase_receiver: (&value.coinbase_receiver).into(),
264 supercharge_coinbase: value.supercharge_coinbase.as_bool(),
265 }
266 }
267}
268
269impl From<&ConsensusState> for v2::ConsensusProofOfStakeDataConsensusStateValueStableV2 {
270 fn from(value: &ConsensusState) -> Self {
271 Self {
272 blockchain_length: value.blockchain_length.as_u32().into(),
273 epoch_count: value.epoch_count.as_u32().into(),
274 min_window_density: value.min_window_density.as_u32().into(),
275 sub_window_densities: value
276 .sub_window_densities
277 .iter()
278 .map(|v| v.as_u32().into())
279 .collect(),
280 last_vrf_output: v2::ConsensusVrfOutputTruncatedStableV1(Vec::new().into()),
282 total_currency: value.total_currency.into(),
283 curr_global_slot_since_hard_fork: v2::ConsensusGlobalSlotStableV1 {
284 slot_number: v2::MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(
285 value.curr_global_slot_since_hard_fork.slot_number.into(),
286 ),
287 slots_per_epoch: value
288 .curr_global_slot_since_hard_fork
289 .slots_per_epoch
290 .into(),
291 },
292 global_slot_since_genesis: v2::MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
293 v2::UnsignedExtendedUInt32StableV1(value.global_slot_since_genesis.as_u32().into()),
294 ),
295 staking_epoch_data: (&value.staking_epoch_data).into(),
296 next_epoch_data: (&value.next_epoch_data).into(),
297 has_ancestor_in_same_checkpoint_window: value.has_ancestor_in_same_checkpoint_window,
298 block_stake_winner: (&value.block_stake_winner).into(),
299 block_creator: (&value.block_creator).into(),
300 coinbase_receiver: (&value.coinbase_receiver).into(),
301 supercharge_coinbase: value.supercharge_coinbase,
302 }
303 }
304}