use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use miden_crypto::merkle::InnerNodeInfo;
use super::script::TransactionScript;
use super::{Felt, Hasher, Word};
use crate::EMPTY_WORD;
use crate::account::auth::{PublicKeyCommitment, Signature};
use crate::note::{NoteId, NoteRecipient};
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
use crate::vm::{AdviceInputs, AdviceMap};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TransactionArgs {
tx_script: Option<TransactionScript>,
tx_script_args: Word,
note_args: BTreeMap<NoteId, Word>,
advice_inputs: AdviceInputs,
auth_args: Word,
}
impl TransactionArgs {
pub fn new(advice_map: AdviceMap) -> Self {
Self::from_parts(
None,
EMPTY_WORD,
BTreeMap::new(),
AdviceInputs::from(advice_map),
EMPTY_WORD,
)
}
pub fn from_parts(
tx_script: Option<TransactionScript>,
tx_script_args: Word,
note_args: BTreeMap<NoteId, Word>,
advice_inputs: AdviceInputs,
auth_args: Word,
) -> Self {
Self {
tx_script,
tx_script_args,
note_args,
advice_inputs,
auth_args,
}
}
#[must_use]
pub fn with_tx_script(mut self, tx_script: TransactionScript) -> Self {
self.tx_script = Some(tx_script);
self
}
#[must_use]
pub fn with_tx_script_and_args(
mut self,
tx_script: TransactionScript,
tx_script_args: Word,
) -> Self {
self.tx_script = Some(tx_script);
self.tx_script_args = tx_script_args;
self
}
#[must_use]
pub fn with_note_args(mut self, note_args: BTreeMap<NoteId, Word>) -> Self {
self.note_args = note_args;
self
}
#[must_use]
pub fn with_auth_args(mut self, auth_args: Word) -> Self {
self.auth_args = auth_args;
self
}
pub fn tx_script(&self) -> Option<&TransactionScript> {
self.tx_script.as_ref()
}
pub fn tx_script_args(&self) -> Word {
self.tx_script_args
}
pub fn get_note_args(&self, note_id: NoteId) -> Option<&Word> {
self.note_args.get(¬e_id)
}
pub fn note_args(&self) -> &BTreeMap<NoteId, Word> {
&self.note_args
}
pub fn advice_inputs(&self) -> &AdviceInputs {
&self.advice_inputs
}
pub fn auth_args(&self) -> Word {
self.auth_args
}
pub fn add_output_note_recipient<T: AsRef<NoteRecipient>>(&mut self, note_recipient: T) {
self.advice_inputs.extend(
AdviceInputs::default().with_map(note_recipient.as_ref().to_advice_map_entries()),
);
}
pub fn add_signature(
&mut self,
pub_key: PublicKeyCommitment,
message: Word,
signature: Signature,
) {
let pk_word: Word = pub_key.into();
self.advice_inputs.extend(AdviceInputs::default().with_map([(
Hasher::merge(&[pk_word, message]),
signature.to_encoded_signature(message),
)]));
}
pub fn extend_output_note_recipients<T, L>(&mut self, notes: L)
where
L: IntoIterator<Item = T>,
T: AsRef<NoteRecipient>,
{
for note in notes {
self.add_output_note_recipient(note);
}
}
pub fn extend_advice_map<T: IntoIterator<Item = (Word, Vec<Felt>)>>(&mut self, iter: T) {
self.advice_inputs.extend(AdviceInputs::default().with_map(iter));
}
pub fn extend_merkle_store<I: Iterator<Item = InnerNodeInfo>>(&mut self, iter: I) {
self.advice_inputs
.extend(AdviceInputs::default().with_merkle_store(iter.collect()));
}
pub fn extend_advice_inputs(&mut self, advice_inputs: AdviceInputs) {
self.advice_inputs.extend(advice_inputs);
}
}
impl Default for TransactionArgs {
fn default() -> Self {
Self::new(AdviceMap::default())
}
}
impl Serializable for TransactionArgs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.tx_script.write_into(target);
self.tx_script_args.write_into(target);
self.note_args.write_into(target);
self.advice_inputs.write_into(target);
self.auth_args.write_into(target);
}
}
impl Deserializable for TransactionArgs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let tx_script = Option::<TransactionScript>::read_from(source)?;
let tx_script_args = Word::read_from(source)?;
let note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
let advice_inputs = AdviceInputs::read_from(source)?;
let auth_args = Word::read_from(source)?;
Ok(Self {
tx_script,
tx_script_args,
note_args,
advice_inputs,
auth_args,
})
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use miden_core::advice::AdviceMap;
use crate::note::Note;
use crate::transaction::TransactionArgs;
use crate::utils::serde::{Deserializable, Serializable};
use crate::vm::AdviceInputs;
use crate::{Felt, Word};
#[test]
fn test_tx_args_serialization() {
let tx_args = TransactionArgs::new(AdviceMap::default());
let bytes: std::vec::Vec<u8> = tx_args.to_bytes();
let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();
assert_eq!(tx_args, decoded);
}
#[test]
fn from_parts_preserves_note_args_and_advice_inputs() {
let note_id = Note::mock_noop(Word::empty()).id();
let note_args = BTreeMap::from([(note_id, Word::new([Felt::from(1_u32); 4]))]);
let advice_inputs = AdviceInputs::default()
.with_map([(Word::new([Felt::from(2_u32); 4]), vec![Felt::from(3_u32)])]);
let tx_args = TransactionArgs::from_parts(
None,
Word::new([Felt::from(4_u32); 4]),
note_args.clone(),
advice_inputs.clone(),
Word::new([Felt::from(5_u32); 4]),
);
assert_eq!(tx_args.note_args(), ¬e_args);
assert_eq!(tx_args.advice_inputs(), &advice_inputs);
assert_eq!(tx_args.tx_script_args(), Word::new([Felt::from(4_u32); 4]));
assert_eq!(tx_args.auth_args(), Word::new([Felt::from(5_u32); 4]));
}
}