Skip to main content

miden_node_proto/domain/
block.rs

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