miden-objects 0.17.0-rc.4

Canonical Protobuf representations for Miden protocol objects
Documentation
use assert_matches::assert_matches;
use miden_protocol::Word;
use miden_protocol::errors::OutputNoteError;
use miden_protocol::note::Note;

use crate::test_utils::error_source;
use crate::{ConversionError, DecodeMessage, Verify, proto};

#[test]
fn input_note_commitment_builds_unchecked_after_decoding() {
    use crate::BuildUnchecked;
    let header = *miden_protocol::note::Note::mock_noop(Word::empty()).header();
    for header in [None, Some(header)] {
        let wire = proto::transaction::InputNoteCommitment {
            nullifier: Some(Word::empty().into()),
            header: header.map(Into::into),
        };
        let built = wire.decode_fields().unwrap().build_unchecked().unwrap();
        assert_eq!(built.nullifier().as_word(), Word::empty());
        assert_eq!(built.header().copied(), header);
    }
    let mut wire = proto::transaction::InputNoteCommitment {
        nullifier: Some(Word::empty().into()),
        header: Some(header.into()),
    };
    wire.header.as_mut().unwrap().metadata.as_mut().unwrap().note_type = 0;
    assert!(wire.decode_fields().unwrap().build_unchecked().is_err());
}

#[test]
fn private_output_note_defers_cross_field_verification() {
    let note = miden_protocol::note::Note::mock_noop(Word::empty());
    let output = miden_protocol::transaction::PrivateOutputNote::new(
        *note.header(),
        note.attachments().clone(),
    )
    .unwrap();
    let mut wire = proto::transaction::PrivateOutputNote::from(&output);
    assert_eq!(wire.clone().decode_fields().unwrap().verify().unwrap(), output);
    wire.header.as_mut().unwrap().metadata.as_mut().unwrap().note_type =
        proto::note::NoteType::Public as i32;
    assert!(wire.decode_fields().unwrap().verify().is_err());
}

#[test]
fn public_output_note_protobuf_rejects_private_note() {
    let note = Note::mock_noop(Word::empty());
    let error = proto::transaction::PublicOutputNote { note: Some(note.clone().into()) }
        .decode_fields()
        .unwrap()
        .verify()
        .map_err(ConversionError::new)
        .unwrap_err();

    assert_matches!(
        error_source::<OutputNoteError>(&error),
        Some(OutputNoteError::NoteIsPrivate(note_id)) if *note_id == note.id()
    );
}