use miden_verifier::ExecutionProof;
use super::{AccountId, Digest, InputNotes, NoteEnvelope, Nullifier, OutputNotes, TransactionId};
use crate::{
accounts::{Account, AccountDelta},
notes::{Note, NoteId},
utils::{
collections::*,
format,
serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
},
};
#[derive(Clone, Debug)]
pub enum AccountDetails {
Full(Account),
Delta(AccountDelta),
}
#[derive(Clone, Debug)]
pub struct ProvenTransaction {
id: TransactionId,
account_id: AccountId,
initial_account_hash: Digest,
final_account_hash: Digest,
account_details: Option<AccountDetails>,
input_notes: InputNotes<Nullifier>,
output_notes: OutputNotes<NoteEnvelope>,
output_note_details: BTreeMap<NoteId, Note>,
tx_script_root: Option<Digest>,
block_ref: Digest,
proof: ExecutionProof,
}
impl ProvenTransaction {
#[allow(clippy::too_many_arguments)]
pub fn new(
account_id: AccountId,
initial_account_hash: Digest,
final_account_hash: Digest,
input_notes: InputNotes<Nullifier>,
output_notes: OutputNotes<NoteEnvelope>,
tx_script_root: Option<Digest>,
block_ref: Digest,
proof: ExecutionProof,
) -> Self {
let id = TransactionId::new(
initial_account_hash,
final_account_hash,
input_notes.commitment(),
output_notes.commitment(),
);
Self {
id,
account_id,
initial_account_hash,
final_account_hash,
account_details: None,
input_notes,
output_notes,
output_note_details: BTreeMap::new(),
tx_script_root,
block_ref,
proof,
}
}
pub fn id(&self) -> TransactionId {
self.id
}
pub fn account_id(&self) -> AccountId {
self.account_id
}
pub fn initial_account_hash(&self) -> Digest {
self.initial_account_hash
}
pub fn final_account_hash(&self) -> Digest {
self.final_account_hash
}
pub fn account_details(&self) -> Option<&AccountDetails> {
self.account_details.as_ref()
}
pub fn input_notes(&self) -> &InputNotes<Nullifier> {
&self.input_notes
}
pub fn output_notes(&self) -> &OutputNotes<NoteEnvelope> {
&self.output_notes
}
pub fn get_output_note_details(&self, note_id: &NoteId) -> Option<&Note> {
self.output_note_details.get(note_id)
}
pub fn tx_script_root(&self) -> Option<Digest> {
self.tx_script_root
}
pub fn proof(&self) -> &ExecutionProof {
&self.proof
}
pub fn block_ref(&self) -> Digest {
self.block_ref
}
}
impl Serializable for AccountDetails {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
match self {
AccountDetails::Full(account) => {
0_u8.write_into(target);
account.write_into(target);
},
AccountDetails::Delta(delta) => {
1_u8.write_into(target);
delta.write_into(target);
},
}
}
}
impl Deserializable for AccountDetails {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match u8::read_from(source)? {
0_u8 => Ok(Self::Full(Account::read_from(source)?)),
1_u8 => Ok(Self::Delta(AccountDelta::read_from(source)?)),
v => Err(DeserializationError::InvalidValue(format!(
"Unknown variant {v} for AccountDetails"
))),
}
}
}
impl Serializable for ProvenTransaction {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.account_id.write_into(target);
self.initial_account_hash.write_into(target);
self.final_account_hash.write_into(target);
self.account_details.write_into(target);
self.input_notes.write_into(target);
self.output_notes.write_into(target);
target.write_usize(self.output_note_details.len());
target.write_many(self.output_note_details.iter());
self.tx_script_root.write_into(target);
self.block_ref.write_into(target);
self.proof.write_into(target);
}
}
impl Deserializable for ProvenTransaction {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let account_id = AccountId::read_from(source)?;
let initial_account_hash = Digest::read_from(source)?;
let final_account_hash = Digest::read_from(source)?;
let account_details = <Option<AccountDetails>>::read_from(source)?;
let input_notes = InputNotes::<Nullifier>::read_from(source)?;
let output_notes = OutputNotes::<NoteEnvelope>::read_from(source)?;
let output_notes_details_len = usize::read_from(source)?;
let details = source.read_many(output_notes_details_len)?;
let output_note_details = BTreeMap::from_iter(details);
let tx_script_root = Deserializable::read_from(source)?;
let block_ref = Digest::read_from(source)?;
let proof = ExecutionProof::read_from(source)?;
let id = TransactionId::new(
initial_account_hash,
final_account_hash,
input_notes.commitment(),
output_notes.commitment(),
);
Ok(Self {
id,
account_id,
initial_account_hash,
final_account_hash,
account_details,
input_notes,
output_notes,
output_note_details,
tx_script_root,
block_ref,
proof,
})
}
}
#[cfg(test)]
mod tests {
use super::ProvenTransaction;
fn check_if_sync<T: Sync>() {}
fn check_if_send<T: Send>() {}
#[test]
fn proven_transaction_is_sync() {
check_if_sync::<ProvenTransaction>();
}
#[test]
fn proven_transaction_is_send() {
check_if_send::<ProvenTransaction>();
}
}