Skip to main content

miden_node_proto/domain/
block.rs

1use std::ops::RangeInclusive;
2
3use miden_protocol::block::{
4    BlockBody,
5    BlockHeader,
6    BlockNumber,
7    BlockSignatures,
8    FeeParameters,
9    SignedBlock,
10    ValidatorKeys,
11};
12use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
13use miden_protocol::utils::serde::Serializable;
14use thiserror::Error;
15
16use crate::decode::{ConversionResultExt, DecodeBytesExt, GrpcDecodeExt};
17use crate::errors::ConversionError;
18use crate::{decode, generated as proto};
19
20// BLOCK NUMBER
21// ================================================================================================
22
23impl From<BlockNumber> for proto::blockchain::BlockNumber {
24    fn from(value: BlockNumber) -> Self {
25        proto::blockchain::BlockNumber { block_num: value.as_u32() }
26    }
27}
28
29impl From<proto::blockchain::BlockNumber> for BlockNumber {
30    fn from(value: proto::blockchain::BlockNumber) -> Self {
31        BlockNumber::from(value.block_num)
32    }
33}
34
35// BLOCK HEADER
36// ================================================================================================
37
38impl From<&BlockHeader> for proto::blockchain::BlockHeader {
39    fn from(header: &BlockHeader) -> Self {
40        Self {
41            version: header.version(),
42            prev_block_commitment: Some(header.prev_block_commitment().into()),
43            block_num: header.block_num().as_u32(),
44            chain_commitment: Some(header.chain_commitment().into()),
45            account_root: Some(header.account_root().into()),
46            nullifier_root: Some(header.nullifier_root().into()),
47            note_root: Some(header.note_root().into()),
48            tx_commitment: Some(header.tx_commitment().into()),
49            tx_kernel_commitment: Some(header.tx_kernel_commitment().into()),
50            validator_keys: header.validator_keys().as_keys().iter().map(Into::into).collect(),
51            timestamp: header.timestamp(),
52            fee_parameters: Some(header.fee_parameters().into()),
53        }
54    }
55}
56
57impl From<BlockHeader> for proto::blockchain::BlockHeader {
58    fn from(header: BlockHeader) -> Self {
59        (&header).into()
60    }
61}
62
63impl TryFrom<&proto::blockchain::BlockHeader> for BlockHeader {
64    type Error = ConversionError;
65
66    fn try_from(value: &proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
67        value.try_into()
68    }
69}
70
71impl TryFrom<proto::blockchain::BlockHeader> for BlockHeader {
72    type Error = ConversionError;
73
74    fn try_from(value: proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
75        let decoder = value.decoder();
76        let prev_block_commitment = decode!(decoder, value.prev_block_commitment)?;
77        let chain_commitment = decode!(decoder, value.chain_commitment)?;
78        let account_root = decode!(decoder, value.account_root)?;
79        let nullifier_root = decode!(decoder, value.nullifier_root)?;
80        let note_root = decode!(decoder, value.note_root)?;
81        let tx_commitment = decode!(decoder, value.tx_commitment)?;
82        let tx_kernel_commitment = decode!(decoder, value.tx_kernel_commitment)?;
83        let validator_keys = value
84            .validator_keys
85            .into_iter()
86            .map(PublicKey::try_from)
87            .collect::<Result<Vec<_>, _>>()
88            .context("validator_keys")?;
89        let validator_keys = ValidatorKeys::new(validator_keys)
90            .map_err(ConversionError::new)
91            .context("validator_keys")?;
92        let fee_parameters = decode!(decoder, value.fee_parameters)?;
93
94        Ok(BlockHeader::new(
95            value.version,
96            prev_block_commitment,
97            value.block_num.into(),
98            chain_commitment,
99            account_root,
100            nullifier_root,
101            note_root,
102            tx_commitment,
103            tx_kernel_commitment,
104            validator_keys,
105            fee_parameters,
106            value.timestamp,
107        ))
108    }
109}
110
111// BLOCK BODY
112// ================================================================================================
113
114impl From<&BlockBody> for proto::blockchain::BlockBody {
115    fn from(body: &BlockBody) -> Self {
116        Self { block_body: body.to_bytes() }
117    }
118}
119
120impl From<BlockBody> for proto::blockchain::BlockBody {
121    fn from(body: BlockBody) -> Self {
122        (&body).into()
123    }
124}
125
126impl TryFrom<&proto::blockchain::BlockBody> for BlockBody {
127    type Error = ConversionError;
128
129    fn try_from(value: &proto::blockchain::BlockBody) -> Result<Self, Self::Error> {
130        value.try_into()
131    }
132}
133
134impl TryFrom<proto::blockchain::BlockBody> for BlockBody {
135    type Error = ConversionError;
136    fn try_from(value: proto::blockchain::BlockBody) -> Result<Self, Self::Error> {
137        BlockBody::decode_bytes(&value.block_body, "BlockBody")
138    }
139}
140
141// SIGNED BLOCK
142// ================================================================================================
143
144impl From<&SignedBlock> for proto::blockchain::SignedBlock {
145    fn from(block: &SignedBlock) -> Self {
146        Self {
147            header: Some(block.header().into()),
148            body: Some(block.body().into()),
149            signatures: block.signatures().as_signatures().iter().map(Into::into).collect(),
150        }
151    }
152}
153
154impl From<SignedBlock> for proto::blockchain::SignedBlock {
155    fn from(block: SignedBlock) -> Self {
156        (&block).into()
157    }
158}
159
160impl TryFrom<&proto::blockchain::SignedBlock> for SignedBlock {
161    type Error = ConversionError;
162
163    fn try_from(value: &proto::blockchain::SignedBlock) -> Result<Self, Self::Error> {
164        value.try_into()
165    }
166}
167
168impl TryFrom<proto::blockchain::SignedBlock> for SignedBlock {
169    type Error = ConversionError;
170    fn try_from(value: proto::blockchain::SignedBlock) -> Result<Self, Self::Error> {
171        let decoder = value.decoder();
172        let header = decode!(decoder, value.header)?;
173        let body = decode!(decoder, value.body)?;
174        let signatures = value
175            .signatures
176            .into_iter()
177            .map(Signature::try_from)
178            .collect::<Result<Vec<_>, _>>()
179            .context("signatures")?;
180        let signatures = BlockSignatures::new(signatures)
181            .map_err(ConversionError::new)
182            .context("signatures")?;
183
184        Ok(SignedBlock::new_unchecked(header, body, signatures))
185    }
186}
187
188// PUBLIC KEY
189// ================================================================================================
190
191impl TryFrom<proto::blockchain::ValidatorPublicKey> for PublicKey {
192    type Error = ConversionError;
193    fn try_from(public_key: proto::blockchain::ValidatorPublicKey) -> Result<Self, Self::Error> {
194        PublicKey::decode_bytes(&public_key.validator_key, "PublicKey")
195    }
196}
197
198impl From<PublicKey> for proto::blockchain::ValidatorPublicKey {
199    fn from(value: PublicKey) -> Self {
200        Self::from(&value)
201    }
202}
203
204impl From<&PublicKey> for proto::blockchain::ValidatorPublicKey {
205    fn from(value: &PublicKey) -> Self {
206        Self { validator_key: value.to_bytes() }
207    }
208}
209
210// SIGNATURE
211// ================================================================================================
212
213impl TryFrom<proto::blockchain::BlockSignature> for Signature {
214    type Error = ConversionError;
215    fn try_from(signature: proto::blockchain::BlockSignature) -> Result<Self, Self::Error> {
216        Signature::decode_bytes(&signature.signature, "Signature")
217    }
218}
219
220impl From<Signature> for proto::blockchain::BlockSignature {
221    fn from(value: Signature) -> Self {
222        Self::from(&value)
223    }
224}
225
226impl From<&Signature> for proto::blockchain::BlockSignature {
227    fn from(value: &Signature) -> Self {
228        Self { signature: value.to_bytes() }
229    }
230}
231
232// FEE PARAMETERS
233// ================================================================================================
234
235impl TryFrom<proto::blockchain::FeeParameters> for FeeParameters {
236    type Error = ConversionError;
237    fn try_from(fee_params: proto::blockchain::FeeParameters) -> Result<Self, Self::Error> {
238        let decoder = fee_params.decoder();
239        let native_asset_id = decode!(decoder, fee_params.native_asset_id)?;
240        Ok(FeeParameters::new(native_asset_id, fee_params.verification_base_fee))
241    }
242}
243
244impl From<FeeParameters> for proto::blockchain::FeeParameters {
245    fn from(value: FeeParameters) -> Self {
246        Self::from(&value)
247    }
248}
249
250impl From<&FeeParameters> for proto::blockchain::FeeParameters {
251    fn from(value: &FeeParameters) -> Self {
252        Self {
253            native_asset_id: Some(value.fee_faucet_id().into()),
254            verification_base_fee: value.verification_base_fee(),
255        }
256    }
257}
258
259// BLOCK RANGE
260// ================================================================================================
261
262#[derive(Debug, Clone, Error, PartialEq, Eq)]
263pub enum InvalidBlockRange {
264    #[error("start ({start}) greater than end ({end})")]
265    StartGreaterThanEnd { start: BlockNumber, end: BlockNumber },
266    #[error("empty range: start ({start})..end ({end})")]
267    EmptyRange { start: BlockNumber, end: BlockNumber },
268}
269
270impl proto::rpc::BlockRange {
271    /// Converts the block range into an inclusive range.
272    pub fn into_inclusive_range<T: From<InvalidBlockRange>>(
273        self,
274    ) -> Result<RangeInclusive<BlockNumber>, T> {
275        let block_range = RangeInclusive::new(self.block_from.into(), self.block_to.into());
276
277        if block_range.start() > block_range.end() {
278            return Err(InvalidBlockRange::StartGreaterThanEnd {
279                start: *block_range.start(),
280                end: *block_range.end(),
281            }
282            .into());
283        }
284
285        if block_range.is_empty() {
286            return Err(InvalidBlockRange::EmptyRange {
287                start: *block_range.start(),
288                end: *block_range.end(),
289            }
290            .into());
291        }
292
293        Ok(block_range)
294    }
295}
296
297impl From<RangeInclusive<BlockNumber>> for proto::rpc::BlockRange {
298    fn from(range: RangeInclusive<BlockNumber>) -> Self {
299        Self {
300            block_from: range.start().as_u32(),
301            block_to: range.end().as_u32(),
302        }
303    }
304}