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