Skip to content

Commit

Permalink
feat: implement serialization for TransactionWitness (#888)
Browse files Browse the repository at this point in the history
  • Loading branch information
SantiagoPittella authored Sep 18, 2024
1 parent adc6626 commit 61d1eb0
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 0.6.0 (TBD)

- Implemented serialization for `TransactionWitness`, `ChainMmr`, `TransactionInputs` and `TransactionArgs` (#888).
- [BREAKING] Renamed the `TransactionProver` struct to `LocalTransactionProver` and added the `TransactionProver` trait (#865).
- Implemented `Display`, `TryFrom<&str>` and `FromStr` for `AccountStorageMode` (#861).
- Implemented offset based storage access (#843).
Expand Down
45 changes: 45 additions & 0 deletions objects/src/transaction/chain_mmr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use alloc::{collections::BTreeMap, vec::Vec};

use vm_core::utils::{Deserializable, Serializable};

use crate::{
crypto::merkle::{InnerNodeInfo, MmrPeaks, PartialMmr},
BlockHeader, ChainMmrError,
Expand Down Expand Up @@ -113,11 +115,37 @@ impl ChainMmr {
}
}

impl Serializable for ChainMmr {
fn write_into<W: miden_crypto::utils::ByteWriter>(&self, target: &mut W) {
self.mmr.write_into(target);
self.blocks.len().write_into(target);
for block in self.blocks.values() {
block.write_into(target);
}
}
}

impl Deserializable for ChainMmr {
fn read_from<R: miden_crypto::utils::ByteReader>(
source: &mut R,
) -> Result<Self, miden_crypto::utils::DeserializationError> {
let mmr = PartialMmr::read_from(source)?;
let block_count = usize::read_from(source)?;
let mut blocks = BTreeMap::new();
for _ in 0..block_count {
let block = BlockHeader::read_from(source)?;
blocks.insert(block.block_num(), block);
}
Ok(Self { mmr, blocks })
}
}
// TESTS
// ================================================================================================

#[cfg(test)]
mod tests {
use vm_core::utils::{Deserializable, Serializable};

use super::ChainMmr;
use crate::{
alloc::vec::Vec,
Expand Down Expand Up @@ -170,6 +198,23 @@ mod tests {
);
}

#[test]
fn tst_chain_mmr_serialization() {
// create chain MMR with 3 blocks - i.e., 2 peaks
let mut mmr = Mmr::default();
for i in 0..3 {
let block_header = int_to_block_header(i);
mmr.add(block_header.hash());
}
let partial_mmr: PartialMmr = mmr.peaks(mmr.forest()).unwrap().into();
let chain_mmr = ChainMmr::new(partial_mmr, Vec::new()).unwrap();

let bytes = chain_mmr.to_bytes();
let deserialized = ChainMmr::read_from_bytes(&bytes).unwrap();

assert_eq!(chain_mmr, deserialized);
}

fn int_to_block_header(block_num: u32) -> BlockHeader {
BlockHeader::new(
0,
Expand Down
22 changes: 22 additions & 0 deletions objects/src/transaction/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,28 @@ impl TransactionInputs {
}
}

impl Serializable for TransactionInputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.account.write_into(target);
self.account_seed.write_into(target);
self.block_header.write_into(target);
self.block_chain.write_into(target);
self.input_notes.write_into(target);
}
}

impl Deserializable for TransactionInputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let account = Account::read_from(source)?;
let account_seed = source.read()?;
let block_header = BlockHeader::read_from(source)?;
let block_chain = ChainMmr::read_from(source)?;
let input_notes = InputNotes::read_from(source)?;
Self::new(account, account_seed, block_header, block_chain, input_notes)
.map_err(|err| DeserializationError::InvalidValue(format!("{}", err)))
}
}

// TO INPUT NOTE COMMITMENT
// ================================================================================================

Expand Down
37 changes: 36 additions & 1 deletion objects/src/transaction/tx_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
/// different from note inputs, as the user executing the transaction can specify arbitrary note
/// args.
/// - Advice inputs: Provides data needed by the runtime, like the details of public output notes.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct TransactionArgs {
tx_script: Option<TransactionScript>,
note_args: BTreeMap<NoteId, Word>,
Expand Down Expand Up @@ -145,6 +145,24 @@ impl TransactionArgs {
}
}

impl Serializable for TransactionArgs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.tx_script.write_into(target);
self.note_args.write_into(target);
self.advice_inputs.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 note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
let advice_inputs = AdviceInputs::read_from(source)?;

Ok(Self { tx_script, note_args, advice_inputs })
}
}

// TRANSACTION SCRIPT
// ================================================================================================

Expand Down Expand Up @@ -245,3 +263,20 @@ impl Deserializable for TransactionScript {
Ok(Self::from_parts(Arc::new(mast), entrypoint, inputs))
}
}

#[cfg(test)]
mod tests {
use vm_core::utils::{Deserializable, Serializable};
use vm_processor::AdviceMap;

use crate::transaction::TransactionArgs;

#[test]
fn test_tx_args_serialization() {
let args = TransactionArgs::new(None, None, AdviceMap::default());
let bytes: std::vec::Vec<u8> = args.to_bytes();
let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();

assert_eq!(args, decoded);
}
}
24 changes: 24 additions & 0 deletions objects/src/transaction/tx_witness.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use vm_core::utils::{ByteReader, Deserializable, Serializable};
use vm_processor::DeserializationError;

use super::{AdviceInputs, TransactionArgs, TransactionInputs};

// TRANSACTION WITNESS
Expand All @@ -20,8 +23,29 @@ use super::{AdviceInputs, TransactionArgs, TransactionInputs};
/// TODO: currently, the advice witness contains redundant and irrelevant data (e.g., tx inputs
/// and tx outputs). we should optimize it to contain only the minimum data required for
/// executing/proving the transaction.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TransactionWitness {
pub tx_inputs: TransactionInputs,
pub tx_args: TransactionArgs,
pub advice_witness: AdviceInputs,
}

// SERIALIZATION
// ================================================================================================

impl Serializable for TransactionWitness {
fn write_into<W: miden_crypto::utils::ByteWriter>(&self, target: &mut W) {
self.tx_inputs.write_into(target);
self.tx_args.write_into(target);
self.advice_witness.write_into(target);
}
}

impl Deserializable for TransactionWitness {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let tx_inputs = TransactionInputs::read_from(source)?;
let tx_args = TransactionArgs::read_from(source)?;
let advice_witness = AdviceInputs::read_from(source)?;
Ok(Self { tx_inputs, tx_args, advice_witness })
}
}

0 comments on commit 61d1eb0

Please sign in to comment.