1use std::collections::BTreeMap;
2use std::ops::RangeInclusive;
3
4use miden_protocol::account::AccountId;
5use miden_protocol::block::nullifier_tree::NullifierWitness;
6use miden_protocol::block::{BlockHeader, BlockInputs, BlockNumber, FeeParameters};
7use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
8use miden_protocol::note::{NoteId, NoteInclusionProof};
9use miden_protocol::transaction::PartialBlockchain;
10use miden_protocol::utils::{Deserializable, Serializable};
11use thiserror::Error;
12
13use crate::errors::{ConversionError, MissingFieldHelper};
14use crate::{AccountWitnessRecord, NullifierWitnessRecord, generated as proto};
15
16impl From<BlockNumber> for proto::blockchain::BlockNumber {
20 fn from(value: BlockNumber) -> Self {
21 proto::blockchain::BlockNumber { block_num: value.as_u32() }
22 }
23}
24
25impl From<proto::blockchain::BlockNumber> for BlockNumber {
26 fn from(value: proto::blockchain::BlockNumber) -> Self {
27 BlockNumber::from(value.block_num)
28 }
29}
30
31impl From<&BlockHeader> for proto::blockchain::BlockHeader {
35 fn from(header: &BlockHeader) -> Self {
36 Self {
37 version: header.version(),
38 prev_block_commitment: Some(header.prev_block_commitment().into()),
39 block_num: header.block_num().as_u32(),
40 chain_commitment: Some(header.chain_commitment().into()),
41 account_root: Some(header.account_root().into()),
42 nullifier_root: Some(header.nullifier_root().into()),
43 note_root: Some(header.note_root().into()),
44 tx_commitment: Some(header.tx_commitment().into()),
45 tx_kernel_commitment: Some(header.tx_kernel_commitment().into()),
46 validator_key: Some(header.validator_key().into()),
47 timestamp: header.timestamp(),
48 fee_parameters: Some(header.fee_parameters().into()),
49 }
50 }
51}
52
53impl From<BlockHeader> for proto::blockchain::BlockHeader {
54 fn from(header: BlockHeader) -> Self {
55 (&header).into()
56 }
57}
58
59impl TryFrom<&proto::blockchain::BlockHeader> for BlockHeader {
60 type Error = ConversionError;
61
62 fn try_from(value: &proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
63 value.try_into()
64 }
65}
66
67impl TryFrom<proto::blockchain::BlockHeader> for BlockHeader {
68 type Error = ConversionError;
69
70 fn try_from(value: proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
71 Ok(BlockHeader::new(
72 value.version,
73 value
74 .prev_block_commitment
75 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(
76 prev_block_commitment
77 )))?
78 .try_into()?,
79 value.block_num.into(),
80 value
81 .chain_commitment
82 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(chain_commitment)))?
83 .try_into()?,
84 value
85 .account_root
86 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(account_root)))?
87 .try_into()?,
88 value
89 .nullifier_root
90 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(nullifier_root)))?
91 .try_into()?,
92 value
93 .note_root
94 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(note_root)))?
95 .try_into()?,
96 value
97 .tx_commitment
98 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(tx_commitment)))?
99 .try_into()?,
100 value
101 .tx_kernel_commitment
102 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(
103 tx_kernel_commitment
104 )))?
105 .try_into()?,
106 value
107 .validator_key
108 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(validator_key)))?
109 .try_into()?,
110 FeeParameters::try_from(value.fee_parameters.ok_or(
111 proto::blockchain::FeeParameters::missing_field(stringify!(fee_parameters)),
112 )?)?,
113 value.timestamp,
114 ))
115 }
116}
117
118impl From<BlockInputs> for proto::store::BlockInputs {
122 fn from(inputs: BlockInputs) -> Self {
123 let (
124 prev_block_header,
125 partial_block_chain,
126 account_witnesses,
127 nullifier_witnesses,
128 unauthenticated_note_proofs,
129 ) = inputs.into_parts();
130
131 proto::store::BlockInputs {
132 latest_block_header: Some(prev_block_header.into()),
133 account_witnesses: account_witnesses
134 .into_iter()
135 .map(|(id, witness)| AccountWitnessRecord { account_id: id, witness }.into())
136 .collect(),
137 nullifier_witnesses: nullifier_witnesses
138 .into_iter()
139 .map(|(nullifier, witness)| {
140 let proof = witness.into_proof();
141 NullifierWitnessRecord { nullifier, proof }.into()
142 })
143 .collect(),
144 partial_block_chain: partial_block_chain.to_bytes(),
145 unauthenticated_note_proofs: unauthenticated_note_proofs
146 .iter()
147 .map(proto::note::NoteInclusionInBlockProof::from)
148 .collect(),
149 }
150 }
151}
152
153impl TryFrom<proto::store::BlockInputs> for BlockInputs {
154 type Error = ConversionError;
155
156 fn try_from(response: proto::store::BlockInputs) -> Result<Self, Self::Error> {
157 let latest_block_header: BlockHeader = response
158 .latest_block_header
159 .ok_or(proto::blockchain::BlockHeader::missing_field("block_header"))?
160 .try_into()?;
161
162 let account_witnesses = response
163 .account_witnesses
164 .into_iter()
165 .map(|entry| {
166 let witness_record: AccountWitnessRecord = entry.try_into()?;
167 Ok((witness_record.account_id, witness_record.witness))
168 })
169 .collect::<Result<BTreeMap<_, _>, ConversionError>>()?;
170
171 let nullifier_witnesses = response
172 .nullifier_witnesses
173 .into_iter()
174 .map(|entry| {
175 let witness: NullifierWitnessRecord = entry.try_into()?;
176 Ok((witness.nullifier, NullifierWitness::new(witness.proof)))
177 })
178 .collect::<Result<BTreeMap<_, _>, ConversionError>>()?;
179
180 let unauthenticated_note_proofs = response
181 .unauthenticated_note_proofs
182 .iter()
183 .map(<(NoteId, NoteInclusionProof)>::try_from)
184 .collect::<Result<_, ConversionError>>()?;
185
186 let partial_block_chain = PartialBlockchain::read_from_bytes(&response.partial_block_chain)
187 .map_err(|source| {
188 ConversionError::deserialization_error("PartialBlockchain", source)
189 })?;
190
191 Ok(BlockInputs::new(
192 latest_block_header,
193 partial_block_chain,
194 account_witnesses,
195 nullifier_witnesses,
196 unauthenticated_note_proofs,
197 ))
198 }
199}
200
201impl TryFrom<proto::blockchain::ValidatorPublicKey> for PublicKey {
205 type Error = ConversionError;
206 fn try_from(public_key: proto::blockchain::ValidatorPublicKey) -> Result<Self, Self::Error> {
207 PublicKey::read_from_bytes(&public_key.validator_key)
208 .map_err(|source| ConversionError::deserialization_error("PublicKey", source))
209 }
210}
211
212impl From<PublicKey> for proto::blockchain::ValidatorPublicKey {
213 fn from(value: PublicKey) -> Self {
214 Self::from(&value)
215 }
216}
217
218impl From<&PublicKey> for proto::blockchain::ValidatorPublicKey {
219 fn from(value: &PublicKey) -> Self {
220 Self { validator_key: value.to_bytes() }
221 }
222}
223
224impl TryFrom<proto::blockchain::BlockSignature> for Signature {
228 type Error = ConversionError;
229 fn try_from(signature: proto::blockchain::BlockSignature) -> Result<Self, Self::Error> {
230 Signature::read_from_bytes(&signature.signature)
231 .map_err(|source| ConversionError::deserialization_error("Signature", source))
232 }
233}
234
235impl From<Signature> for proto::blockchain::BlockSignature {
236 fn from(value: Signature) -> Self {
237 Self::from(&value)
238 }
239}
240
241impl From<&Signature> for proto::blockchain::BlockSignature {
242 fn from(value: &Signature) -> Self {
243 Self { signature: value.to_bytes() }
244 }
245}
246
247impl TryFrom<proto::blockchain::FeeParameters> for FeeParameters {
251 type Error = ConversionError;
252 fn try_from(fee_params: proto::blockchain::FeeParameters) -> Result<Self, Self::Error> {
253 let native_asset_id = fee_params.native_asset_id.map(AccountId::try_from).ok_or(
254 proto::blockchain::FeeParameters::missing_field(stringify!(native_asset_id)),
255 )??;
256 let fee_params = FeeParameters::new(native_asset_id, fee_params.verification_base_fee)?;
257 Ok(fee_params)
258 }
259}
260
261impl From<FeeParameters> for proto::blockchain::FeeParameters {
262 fn from(value: FeeParameters) -> Self {
263 Self::from(&value)
264 }
265}
266
267impl From<&FeeParameters> for proto::blockchain::FeeParameters {
268 fn from(value: &FeeParameters) -> Self {
269 Self {
270 native_asset_id: Some(value.native_asset_id().into()),
271 verification_base_fee: value.verification_base_fee(),
272 }
273 }
274}
275
276#[derive(Debug, Clone, Error, PartialEq, Eq)]
280pub enum InvalidBlockRange {
281 #[error("start ({start}) greater than end ({end})")]
282 StartGreaterThanEnd { start: BlockNumber, end: BlockNumber },
283 #[error("empty range: start ({start})..end ({end})")]
284 EmptyRange { start: BlockNumber, end: BlockNumber },
285}
286
287impl proto::rpc::BlockRange {
288 pub fn into_inclusive_range<T: From<InvalidBlockRange>>(
291 self,
292 fallback: &BlockNumber,
293 ) -> Result<RangeInclusive<BlockNumber>, T> {
294 let block_range = RangeInclusive::new(
295 self.block_from.into(),
296 self.block_to.map_or(*fallback, BlockNumber::from),
297 );
298
299 if block_range.start() > block_range.end() {
300 return Err(InvalidBlockRange::StartGreaterThanEnd {
301 start: *block_range.start(),
302 end: *block_range.end(),
303 }
304 .into());
305 }
306
307 if block_range.is_empty() {
308 return Err(InvalidBlockRange::EmptyRange {
309 start: *block_range.start(),
310 end: *block_range.end(),
311 }
312 .into());
313 }
314
315 Ok(block_range)
316 }
317}
318
319impl From<RangeInclusive<BlockNumber>> for proto::rpc::BlockRange {
320 fn from(range: RangeInclusive<BlockNumber>) -> Self {
321 Self {
322 block_from: range.start().as_u32(),
323 block_to: Some(range.end().as_u32()),
324 }
325 }
326}