diff --git a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs index 396ac47c9df..60f486cd921 100644 --- a/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs +++ b/crates/starknet_transaction_prover/src/proving/virtual_snos_prover.rs @@ -19,7 +19,7 @@ use starknet_api::execution_resources::GasAmount; use starknet_api::rpc_transaction::{RpcInvokeTransaction, RpcInvokeTransactionV3, RpcTransaction}; use starknet_api::transaction::fields::{Proof, ProofFacts, Tip}; use starknet_api::transaction::{InvokeTransaction, MessageToL1}; -use tracing::{info, instrument}; +use tracing::{info, instrument, warn}; use url::Url; use crate::blocking_check::{BlockingCheckClient, BlockingCheckResult}; @@ -179,16 +179,28 @@ impl VirtualSnosProver { block_id: BlockId, transaction: RpcTransaction, ) -> Result { - // Validate block_id is not pending. + // Each validation site emits a structured warn before returning so + // the failing field is grep-able directly. Transaction calldata is + // private user data — never logged. if matches!(block_id, BlockId::Pending) { + warn!(event = "validation_error", reason = "pending_block_unsupported"); return Err(VirtualSnosProverError::ValidationError( "Pending blocks are not supported; only finalized blocks can be proven." .to_string(), )); } - let invoke_v3 = extract_rpc_invoke_tx(transaction.clone())?; - validate_transaction_input(&invoke_v3, self.validate_zero_fee_fields)?; + let invoke_v3 = extract_rpc_invoke_tx(transaction.clone()).inspect_err(|err| { + warn!(event = "validation_error", reason = "non_invoke_transaction", error = %err); + })?; + validate_transaction_input(&invoke_v3, self.validate_zero_fee_fields).inspect_err( + |_err| { + // No `error` field: an invalid-input message can embed the client's fee inputs + // (max_price_per_unit / tip); the full message still reaches the client via the + // RPC error. + warn!(event = "validation_error", reason = "invalid_transaction_input"); + }, + )?; let invoke_tx = InvokeTransaction::V3(invoke_v3.into()); match &self.blocking_check_client { diff --git a/crates/starknet_transaction_prover/src/server/rpc_impl.rs b/crates/starknet_transaction_prover/src/server/rpc_impl.rs index d18f6d84b05..de6de8a46d3 100644 --- a/crates/starknet_transaction_prover/src/server/rpc_impl.rs +++ b/crates/starknet_transaction_prover/src/server/rpc_impl.rs @@ -145,7 +145,22 @@ impl ProvingRpcServer for ProvingRpcServerImpl { }; self.prover.prove_transaction(block_id, transaction).await.map_err(|err| { - warn!("prove_transaction failed: {:?}", err); + // `outcome` matches `prover_prove_transaction_outcome_total` so log queries and metric + // filters share one vocabulary. Validation failures can embed the client's fee inputs + // in their message, so omit `error` for them; the origin-level warn in + // `virtual_snos_prover` already logged the reason. Other outcomes originate internally + // with no fee data, so logging their `error` is safe. + let outcome = err.metric_outcome(); + if outcome == outcomes::VALIDATION { + warn!(event = "prove_transaction_failed", outcome, "prove_transaction failed"); + } else { + warn!( + event = "prove_transaction_failed", + outcome, + error = %err, + "prove_transaction failed", + ); + } ErrorObjectOwned::from(err) }) }