diff --git a/miden-tx/Cargo.toml b/miden-tx/Cargo.toml index a0494e0e4..7a48fa240 100644 --- a/miden-tx/Cargo.toml +++ b/miden-tx/Cargo.toml @@ -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 } diff --git a/miden-tx/src/error.rs b/miden-tx/src/error.rs index 59de53d8b..0bb130c21 100644 --- a/miden-tx/src/error.rs +++ b/miden-tx/src/error.rs @@ -1,4 +1,4 @@ -use core::fmt; +use core::fmt::{self, Display}; use miden_objects::{ assembly::AssemblyError, notes::NoteId, transaction::ProvenTransactionBuilderError, Felt, @@ -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 // ================================================================================================ diff --git a/miden-tx/src/prover/mod.rs b/miden-tx/src/prover/mod.rs index 8dcde959d..7e54ae238 100644 --- a/miden-tx/src/prover/mod.rs +++ b/miden-tx/src/prover/mod.rs @@ -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; @@ -30,6 +32,10 @@ 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. @@ -37,6 +43,7 @@ impl TransactionProver { pub fn prove_transaction>( &self, transaction: T, + on_chain_account: bool, ) -> Result { let tx_witness: TransactionWitness = transaction.into(); @@ -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)?; @@ -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) } } diff --git a/miden-tx/src/tests.rs b/miden-tx/src/tests.rs index beac1128d..4cfce5ed6 100644 --- a/miden-tx/src/tests.rs +++ b/miden-tx/src/tests.rs @@ -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(); diff --git a/miden-tx/tests/integration/main.rs b/miden-tx/tests/integration/main.rs index 4abc95e1b..0ced4339f 100644 --- a/miden-tx/tests/integration/main.rs +++ b/miden-tx/tests/integration/main.rs @@ -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(); diff --git a/objects/Cargo.toml b/objects/Cargo.toml index fedf9b205..7f7b59deb 100644 --- a/objects/Cargo.toml +++ b/objects/Cargo.toml @@ -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 = [ diff --git a/objects/src/transaction/mod.rs b/objects/src/transaction/mod.rs index d29dd1dbe..913b99434 100644 --- a/objects/src/transaction/mod.rs +++ b/objects/src/transaction/mod.rs @@ -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; diff --git a/objects/src/transaction/proven_tx.rs b/objects/src/transaction/proven_tx.rs index 5884e7387..1be3bf055 100644 --- a/objects/src/transaction/proven_tx.rs +++ b/objects/src/transaction/proven_tx.rs @@ -1,3 +1,5 @@ +use core::fmt::Display; + use miden_verifier::ExecutionProof; use super::{AccountId, Digest, InputNotes, NoteEnvelope, Nullifier, OutputNotes, TransactionId}; @@ -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), } +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 // -------------------------------------------------------------------------------------------- @@ -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 {