miden-objects 0.17.0-rc.4

Canonical Protobuf representations for Miden protocol objects
Documentation
use alloc::vec;

use assert_matches::assert_matches;
use miden_protocol::Word;
use miden_protocol::asset::AssetId;
use miden_protocol::errors::ProtocolConfigError;
use miden_protocol::protocol_config::KernelConfig;

use crate::decoded::account::test_utils::dummy_account_id;
use crate::decoded::protocol_config::test_utils::dummy_protocol_config;
use crate::test_utils::error_source;
use crate::{ConversionError, DecodeMessage, Verify, proto};

#[test]
fn kernel_verification_is_deferred() {
    let decoded = proto::protocol_config::KernelConfig {
        main_proc: Some(Word::empty().into()),
        kernel_procs: vec![
            Word::empty().into();
            miden_protocol::protocol_config::KernelConfig::MAX_NUM_KERNEL_PROCEDURES
                + 1
        ],
    }
    .decode_fields()
    .unwrap();
    assert!(decoded.verify().is_err());
}

#[test]
fn security_policy_verification_is_deferred() {
    for minimum_bits in [0, u32::MAX] {
        let decoded = proto::protocol_config::ProofSecurityPolicy {
            security_estimator_root: Some(Word::empty().into()),
            minimum_bits,
        }
        .decode_fields()
        .unwrap();
        assert_eq!(decoded.minimum_bits, minimum_bits);
        assert!(decoded.verify().is_err());
    }
}

#[test]
fn proof_verification_config_defers_nested_policy_checks() {
    let decoded = proto::protocol_config::ProofVerificationConfig {
        vm_verifier_root: Some(Word::empty().into()),
        precompile_verifier_root: Some(Word::empty().into()),
        security_policy: Some(proto::protocol_config::ProofSecurityPolicy {
            security_estimator_root: Some(Word::empty().into()),
            minimum_bits: 0,
        }),
    }
    .decode_fields()
    .unwrap();
    assert!(decoded.verify().is_err());
}

#[test]
fn protocol_config_preserves_fee_asset_validation_source() {
    let mut message = proto::protocol_config::ProtocolConfig::from(dummy_protocol_config());
    let non_fungible = AssetId::new(
        miden_protocol::asset::AssetClass::default(),
        dummy_account_id(10),
        miden_protocol::asset::AssetComposition::None,
    )
    .unwrap();
    message.fee_asset_id = Some(Word::from(non_fungible).into());

    let error = message
        .decode_fields()
        .unwrap()
        .verify()
        .map_err(ConversionError::new)
        .unwrap_err();

    assert_matches!(
        error_source::<ProtocolConfigError>(&error),
        Some(ProtocolConfigError::FeeAssetMustBeFungible(_))
    );
}

#[test]
fn kernel_config_rejects_oversized_procedure_list() {
    let error = proto::protocol_config::KernelConfig {
        main_proc: Some(Word::empty().into()),
        kernel_procs: vec![Word::empty().into(); KernelConfig::MAX_NUM_KERNEL_PROCEDURES + 1],
    }
    .decode_fields()
    .unwrap()
    .verify()
    .map_err(ConversionError::new)
    .unwrap_err();

    assert_matches!(
        error_source::<ProtocolConfigError>(&error),
        Some(ProtocolConfigError::TooManyKernelProcedures { count })
            if *count == KernelConfig::MAX_NUM_KERNEL_PROCEDURES + 1
    );
}

#[test]
fn proof_security_policy_rejects_out_of_range_minimum_bits() {
    let error = proto::protocol_config::ProofSecurityPolicy {
        security_estimator_root: Some(Word::empty().into()),
        minimum_bits: u32::from(u8::MAX) + 1,
    }
    .decode_fields()
    .unwrap()
    .verify()
    .map_err(ConversionError::new)
    .unwrap_err();

    assert_matches!(error_source::<core::num::TryFromIntError>(&error), Some(_));
}

#[test]
fn proof_security_policy_preserves_zero_bits_validation_source() {
    let error = proto::protocol_config::ProofSecurityPolicy {
        security_estimator_root: Some(Word::empty().into()),
        minimum_bits: 0,
    }
    .decode_fields()
    .unwrap()
    .verify()
    .map_err(ConversionError::new)
    .unwrap_err();

    assert_matches!(
        error_source::<ProtocolConfigError>(&error),
        Some(ProtocolConfigError::MinimumSecurityBitsMustBeNonZero)
    );
}

#[test]
fn protocol_config_decodes_all_fields_before_verification() {
    use crate::{DecodeMessage, Verify};
    let config = dummy_protocol_config();
    let decoded = proto::protocol_config::ProtocolConfig::from(&config).decode_fields().unwrap();
    assert_eq!(decoded.tx_kernel.kernel_procs, config.tx_kernel().kernel_procs());
    assert_eq!(decoded.verify().unwrap(), config);
}