use std::ops::RangeInclusive;
use miden_protocol::account::AccountId;
use miden_protocol::block::{BlockBody, BlockHeader, BlockNumber, FeeParameters, SignedBlock};
use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
use miden_protocol::utils::serde::Serializable;
use thiserror::Error;
use crate::decode::{ConversionResultExt, DecodeBytesExt, GrpcDecodeExt};
use crate::errors::ConversionError;
use crate::{decode, generated as proto};
impl From<BlockNumber> for proto::blockchain::BlockNumber {
fn from(value: BlockNumber) -> Self {
proto::blockchain::BlockNumber { block_num: value.as_u32() }
}
}
impl From<proto::blockchain::BlockNumber> for BlockNumber {
fn from(value: proto::blockchain::BlockNumber) -> Self {
BlockNumber::from(value.block_num)
}
}
impl From<&BlockHeader> for proto::blockchain::BlockHeader {
fn from(header: &BlockHeader) -> Self {
Self {
version: header.version(),
prev_block_commitment: Some(header.prev_block_commitment().into()),
block_num: header.block_num().as_u32(),
chain_commitment: Some(header.chain_commitment().into()),
account_root: Some(header.account_root().into()),
nullifier_root: Some(header.nullifier_root().into()),
note_root: Some(header.note_root().into()),
tx_commitment: Some(header.tx_commitment().into()),
tx_kernel_commitment: Some(header.tx_kernel_commitment().into()),
validator_key: Some(header.validator_key().into()),
timestamp: header.timestamp(),
fee_parameters: Some(header.fee_parameters().into()),
}
}
}
impl From<BlockHeader> for proto::blockchain::BlockHeader {
fn from(header: BlockHeader) -> Self {
(&header).into()
}
}
impl TryFrom<&proto::blockchain::BlockHeader> for BlockHeader {
type Error = ConversionError;
fn try_from(value: &proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
value.try_into()
}
}
impl TryFrom<proto::blockchain::BlockHeader> for BlockHeader {
type Error = ConversionError;
fn try_from(value: proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
let decoder = value.decoder();
let prev_block_commitment = decode!(decoder, value.prev_block_commitment)?;
let chain_commitment = decode!(decoder, value.chain_commitment)?;
let account_root = decode!(decoder, value.account_root)?;
let nullifier_root = decode!(decoder, value.nullifier_root)?;
let note_root = decode!(decoder, value.note_root)?;
let tx_commitment = decode!(decoder, value.tx_commitment)?;
let tx_kernel_commitment = decode!(decoder, value.tx_kernel_commitment)?;
let validator_key = decode!(decoder, value.validator_key)?;
let fee_parameters = decode!(decoder, value.fee_parameters)?;
Ok(BlockHeader::new(
value.version,
prev_block_commitment,
value.block_num.into(),
chain_commitment,
account_root,
nullifier_root,
note_root,
tx_commitment,
tx_kernel_commitment,
validator_key,
fee_parameters,
value.timestamp,
))
}
}
impl From<&BlockBody> for proto::blockchain::BlockBody {
fn from(body: &BlockBody) -> Self {
Self { block_body: body.to_bytes() }
}
}
impl From<BlockBody> for proto::blockchain::BlockBody {
fn from(body: BlockBody) -> Self {
(&body).into()
}
}
impl TryFrom<&proto::blockchain::BlockBody> for BlockBody {
type Error = ConversionError;
fn try_from(value: &proto::blockchain::BlockBody) -> Result<Self, Self::Error> {
value.try_into()
}
}
impl TryFrom<proto::blockchain::BlockBody> for BlockBody {
type Error = ConversionError;
fn try_from(value: proto::blockchain::BlockBody) -> Result<Self, Self::Error> {
BlockBody::decode_bytes(&value.block_body, "BlockBody")
}
}
impl From<&SignedBlock> for proto::blockchain::SignedBlock {
fn from(block: &SignedBlock) -> Self {
Self {
header: Some(block.header().into()),
body: Some(block.body().into()),
signature: Some(block.signature().into()),
}
}
}
impl From<SignedBlock> for proto::blockchain::SignedBlock {
fn from(block: SignedBlock) -> Self {
(&block).into()
}
}
impl TryFrom<&proto::blockchain::SignedBlock> for SignedBlock {
type Error = ConversionError;
fn try_from(value: &proto::blockchain::SignedBlock) -> Result<Self, Self::Error> {
value.try_into()
}
}
impl TryFrom<proto::blockchain::SignedBlock> for SignedBlock {
type Error = ConversionError;
fn try_from(value: proto::blockchain::SignedBlock) -> Result<Self, Self::Error> {
let decoder = value.decoder();
let header = decode!(decoder, value.header)?;
let body = decode!(decoder, value.body)?;
let signature = decode!(decoder, value.signature)?;
Ok(SignedBlock::new_unchecked(header, body, signature))
}
}
impl TryFrom<proto::blockchain::ValidatorPublicKey> for PublicKey {
type Error = ConversionError;
fn try_from(public_key: proto::blockchain::ValidatorPublicKey) -> Result<Self, Self::Error> {
PublicKey::decode_bytes(&public_key.validator_key, "PublicKey")
}
}
impl From<PublicKey> for proto::blockchain::ValidatorPublicKey {
fn from(value: PublicKey) -> Self {
Self::from(&value)
}
}
impl From<&PublicKey> for proto::blockchain::ValidatorPublicKey {
fn from(value: &PublicKey) -> Self {
Self { validator_key: value.to_bytes() }
}
}
impl TryFrom<proto::blockchain::BlockSignature> for Signature {
type Error = ConversionError;
fn try_from(signature: proto::blockchain::BlockSignature) -> Result<Self, Self::Error> {
Signature::decode_bytes(&signature.signature, "Signature")
}
}
impl From<Signature> for proto::blockchain::BlockSignature {
fn from(value: Signature) -> Self {
Self::from(&value)
}
}
impl From<&Signature> for proto::blockchain::BlockSignature {
fn from(value: &Signature) -> Self {
Self { signature: value.to_bytes() }
}
}
impl TryFrom<proto::blockchain::FeeParameters> for FeeParameters {
type Error = ConversionError;
fn try_from(fee_params: proto::blockchain::FeeParameters) -> Result<Self, Self::Error> {
let native_asset_id = fee_params
.native_asset_id
.map(AccountId::try_from)
.ok_or(ConversionError::missing_field::<proto::blockchain::FeeParameters>(
"native_asset_id",
))?
.context("native_asset_id")?;
let fee_params = FeeParameters::new(native_asset_id, fee_params.verification_base_fee);
Ok(fee_params)
}
}
impl From<FeeParameters> for proto::blockchain::FeeParameters {
fn from(value: FeeParameters) -> Self {
Self::from(&value)
}
}
impl From<&FeeParameters> for proto::blockchain::FeeParameters {
fn from(value: &FeeParameters) -> Self {
Self {
native_asset_id: Some(value.fee_faucet_id().into()),
verification_base_fee: value.verification_base_fee(),
}
}
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum InvalidBlockRange {
#[error("start ({start}) greater than end ({end})")]
StartGreaterThanEnd { start: BlockNumber, end: BlockNumber },
#[error("empty range: start ({start})..end ({end})")]
EmptyRange { start: BlockNumber, end: BlockNumber },
}
impl proto::rpc::BlockRange {
pub fn into_inclusive_range<T: From<InvalidBlockRange>>(
self,
) -> Result<RangeInclusive<BlockNumber>, T> {
let block_range = RangeInclusive::new(self.block_from.into(), self.block_to.into());
if block_range.start() > block_range.end() {
return Err(InvalidBlockRange::StartGreaterThanEnd {
start: *block_range.start(),
end: *block_range.end(),
}
.into());
}
if block_range.is_empty() {
return Err(InvalidBlockRange::EmptyRange {
start: *block_range.start(),
end: *block_range.end(),
}
.into());
}
Ok(block_range)
}
}
impl From<RangeInclusive<BlockNumber>> for proto::rpc::BlockRange {
fn from(range: RangeInclusive<BlockNumber>) -> Self {
Self {
block_from: range.start().as_u32(),
block_to: range.end().as_u32(),
}
}
}