Skip to content

Commit

Permalink
tx-prover: Add account on-chain state tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
hackaugusto committed Feb 27, 2024
1 parent 3a1b094 commit 7a4a711
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 32 deletions.
1 change: 0 additions & 1 deletion miden-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ miden-objects = { package = "miden-objects", path = "../objects", default-featur
miden-prover = { package = "miden-prover", git = "https://github.com/0xPolygonMiden/miden-vm", branch = "next", default-features = false }
miden-verifier = { workspace = true }
vm-processor = { workspace = true }
thiserror = { version = "1.0" }

[dev-dependencies]
mock = { package = "miden-mock", path = "../mock", default-features = false }
31 changes: 23 additions & 8 deletions miden-tx/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::fmt;
use core::fmt::{self, Display};

use miden_objects::{
assembly::AssemblyError, notes::NoteId, transaction::ProvenTransactionBuilderError, Felt,
Expand Down Expand Up @@ -70,16 +70,31 @@ impl std::error::Error for TransactionExecutorError {}
// ================================================================================================

#[derive(Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum TransactionProverError {
#[error("Proving transaction failed: {0}")]
ProveTransactionProgramFailed(#[from] ExecutionError),
#[error("Transaction ouptut invalid: {0}")]
InvalidTransactionOutput(#[from] TransactionOutputError),
#[error("Building proven transaction error: {0}")]
ProvenTransactionBuilderError(#[from] ProvenTransactionBuilderError),
ProveTransactionProgramFailed(ExecutionError),
InvalidTransactionOutput(TransactionOutputError),
ProvenTransactionBuilderError(ProvenTransactionBuilderError),
}

impl Display for TransactionProverError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TransactionProverError::ProveTransactionProgramFailed(inner) => {
write!(f, "Proving transaction failed: {}", inner)
},
TransactionProverError::InvalidTransactionOutput(inner) => {
write!(f, "Transaction ouptut invalid: {}", inner)
},
TransactionProverError::ProvenTransactionBuilderError(inner) => {
write!(f, "Building proven transaction error: {}", inner)
},
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for TransactionProverError {}

// TRANSACTION VERIFIER ERROR
// ================================================================================================

Expand Down
26 changes: 23 additions & 3 deletions miden-tx/src/prover/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use miden_lib::transaction::{ToTransactionKernelInputs, TransactionKernel};
use miden_objects::{
notes::{NoteEnvelope, Nullifier},
transaction::{InputNotes, ProvenTransaction, ProvenTransactionBuilder, TransactionWitness},
transaction::{
AccountDetails, InputNotes, ProvenTransaction, ProvenTransactionBuilder, TransactionWitness,
},
};
use miden_prover::prove;
pub use miden_prover::ProvingOptions;
Expand Down Expand Up @@ -30,13 +32,18 @@ impl TransactionProver {

/// Proves the provided transaction and returns a [ProvenTransaction].
///
/// # Args
///
/// on_chain_account: determines if the account state is on-chain.
///
/// # Errors
/// - If the consumed note data in the transaction witness is corrupt.
/// - If the transaction program cannot be proven.
/// - If the transaction result is corrupt.
pub fn prove_transaction<T: Into<TransactionWitness>>(
&self,
transaction: T,
on_chain_account: bool,
) -> Result<ProvenTransaction, TransactionProverError> {
let tx_witness: TransactionWitness = transaction.into();

Expand All @@ -57,7 +64,7 @@ impl TransactionProver {
.map_err(TransactionProverError::ProveTransactionProgramFailed)?;

// extract transaction outputs and process transaction data
let (advice_provider, _event_handler) = host.into_parts();
let (advice_provider, account_delta) = host.into_parts();
let (_, map, _) = advice_provider.into_parts();
let tx_outputs = TransactionKernel::parse_transaction_outputs(&stack_outputs, &map.into())
.map_err(TransactionProverError::InvalidTransactionOutput)?;
Expand All @@ -82,6 +89,19 @@ impl TransactionProver {
_ => builder,
};

Ok(builder.build()?)
let builder = match on_chain_account {
true => {
let account_details = if tx_witness.account().is_new() {
AccountDetails::Full(tx_witness.account().clone())
} else {
AccountDetails::Delta(account_delta)
};

builder.account_details(account_details)
},
false => builder,
};

builder.build().map_err(TransactionProverError::ProvenTransactionBuilderError)
}
}
2 changes: 1 addition & 1 deletion miden-tx/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ fn prove_witness_and_verify() {
// Prove the transaction with the witness
let proof_options = ProvingOptions::default();
let prover = TransactionProver::new(proof_options);
let proven_transaction = prover.prove_transaction(executed_transaction).unwrap();
let proven_transaction = prover.prove_transaction(executed_transaction, false).unwrap();

// Serialize & deserialize the ProvenTransaction
let serialised_transaction = proven_transaction.to_bytes();
Expand Down
2 changes: 1 addition & 1 deletion miden-tx/tests/integration/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub fn prove_and_verify_transaction(
// Prove the transaction
let proof_options = ProvingOptions::default();
let prover = TransactionProver::new(proof_options);
let proven_transaction = prover.prove_transaction(executed_transaction).unwrap();
let proven_transaction = prover.prove_transaction(executed_transaction, false).unwrap();

// Serialize & deserialize the ProvenTransaction
let serialised_transaction = proven_transaction.to_bytes();
Expand Down
1 change: 0 additions & 1 deletion objects/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ miden-verifier = { workspace = true }
serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] }
vm-core = { package = "miden-core", git = "https://github.com/0xPolygonMiden/miden-vm", branch = "next", default-features = false }
vm-processor = { workspace = true }
thiserror = { version = "1.0" }

[dev-dependencies]
criterion = { version = "0.5", default-features = false, features = [
Expand Down
4 changes: 3 additions & 1 deletion objects/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ pub use executed_tx::ExecutedTransaction;
pub use inputs::{InputNote, InputNotes, TransactionInputs};
pub use outputs::{OutputNote, OutputNotes, TransactionOutputs};
pub use prepared_tx::PreparedTransaction;
pub use proven_tx::{ProvenTransaction, ProvenTransactionBuilder, ProvenTransactionBuilderError};
pub use proven_tx::{
AccountDetails, ProvenTransaction, ProvenTransactionBuilder, ProvenTransactionBuilderError,
};
pub use transaction_id::TransactionId;
pub use tx_args::{TransactionArgs, TransactionScript};
pub use tx_witness::TransactionWitness;
77 changes: 61 additions & 16 deletions objects/src/transaction/proven_tx.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::fmt::Display;

use miden_verifier::ExecutionProof;

use super::{AccountId, Digest, InputNotes, NoteEnvelope, Nullifier, OutputNotes, TransactionId};
Expand Down Expand Up @@ -161,35 +163,76 @@ pub struct ProvenTransactionBuilder {
}

#[derive(Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum ProvenTransactionBuilderError {
#[error("A ProvenTransaction can not be created without an account id.")]
MissingAccountId,
#[error("A ProvenTransaction can not be created without the account's initial hash.")]
MissingInitialHash,
#[error("A ProvenTransaction can not be created without the account's final hash.")]
MissingFinalHash,
#[error("A ProvenTransaction can not be created without a reference block.")]
MissingBlockReference,
#[error("A ProvenTransaction can not be created without the execution proof.")]
MissingExecutionProof,

#[error("Note detail {0} for an unknown output note.")]
InvalidNoteDetail(NoteId, Note),

#[error("Provent transaction account_id {0} and account_details.id must match {1}.")]
AccountIdMismatch(AccountId, AccountId),

#[error("Provent transaction account_final_hash {0} and account_details.hash must match {1}.")]
AccountFinalHashMismatch(Digest, Digest),
#[error("Invalid input notes: {0}")]
InputNotesError(#[from] TransactionInputError),
#[error("Invalid output notes: {0}")]
OutputNotesError(#[from] TransactionOutputError),
#[error("Note details for unknown note ids: {0:?}")]
InputNotesError(TransactionInputError),
OutputNotesError(TransactionOutputError),
NoteDetailsForUnknownNotes(Vec<NoteId>),
}

impl Display for ProvenTransactionBuilderError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ProvenTransactionBuilderError::MissingAccountId => {
write!(f, "A ProvenTransaction can not be created without an account id.")
},
ProvenTransactionBuilderError::MissingInitialHash => {
write!(
f,
"A ProvenTransaction can not be created without the account's initial hash."
)
},
ProvenTransactionBuilderError::MissingFinalHash => {
write!(
f,
"A ProvenTransaction can not be created without the account's final hash."
)
},
ProvenTransactionBuilderError::MissingBlockReference => {
write!(f, "A ProvenTransaction can not be created without a reference block.")
},
ProvenTransactionBuilderError::MissingExecutionProof => {
write!(f, "A ProvenTransaction can not be created without the execution proof.")
},
ProvenTransactionBuilderError::InvalidNoteDetail(id, _note) => {
write!(f, "Note detail {} for an unknown output note.", id)
},
ProvenTransactionBuilderError::AccountIdMismatch(tx_id, details_id) => {
write!(
f,
"Provent transaction account_id {} and account_details.id must match {}.",
tx_id, details_id,
)
},
ProvenTransactionBuilderError::AccountFinalHashMismatch(tx_digest, details_hash) => {
write!(f, "Provent transaction account_final_hash {} and account_details.hash must match {}.", tx_digest, details_hash)
},
ProvenTransactionBuilderError::InputNotesError(inner) => {
write!(f, "Invalid input notes: {}", inner)
},
ProvenTransactionBuilderError::OutputNotesError(inner) => {
write!(f, "Invalid output notes: {}", inner)
},
ProvenTransactionBuilderError::NoteDetailsForUnknownNotes(note_ids) => {
write!(f, "Note details for unknown note ids: {:?}", note_ids)
},
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for ProvenTransactionBuilderError {}

impl ProvenTransactionBuilder {
// CONSTRUCTOR
// --------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -313,8 +356,10 @@ impl ProvenTransactionBuilder {
}

let account_details = self.account_details.take();
let input_notes = InputNotes::new(self.input_notes)?;
let output_notes = OutputNotes::new(self.output_notes)?;
let input_notes = InputNotes::new(self.input_notes)
.map_err(ProvenTransactionBuilderError::InputNotesError)?;
let output_notes = OutputNotes::new(self.output_notes)
.map_err(ProvenTransactionBuilderError::OutputNotesError)?;
let tx_script_root = self.tx_script_root;

if let Some(ref details) = account_details {
Expand Down

0 comments on commit 7a4a711

Please sign in to comment.