77
88use anyhow:: { Context , Result } ;
99use clap:: { Parser , Subcommand } ;
10- use echidna:: { ProverConfig , ProverKind } ;
10+ use echidna:: {
11+ diagnostics:: proof_failure:: diagnose_from_outcome, provers:: ProverBackend , ProverConfig ,
12+ ProverKind ,
13+ } ;
1114use indicatif:: { ProgressBar , ProgressStyle } ;
1215use std:: path:: PathBuf ;
1316use tracing:: { info, warn} ;
@@ -66,6 +69,10 @@ enum Commands {
6669 /// Library paths
6770 #[ arg( long) ]
6871 library : Vec < PathBuf > ,
72+
73+ /// On failure, run diagnostics and explain why the proof failed
74+ #[ arg( long) ]
75+ diagnose : bool ,
6976 } ,
7077
7178 /// Verify an existing proof
@@ -88,6 +95,10 @@ enum Commands {
8895 /// Library paths
8996 #[ arg( long) ]
9097 library : Vec < PathBuf > ,
98+
99+ /// On failure, run diagnostics and explain why the proof failed
100+ #[ arg( long) ]
101+ diagnose : bool ,
91102 } ,
92103
93104 /// Search theorem libraries
@@ -172,9 +183,10 @@ async fn main() -> Result<()> {
172183 neural,
173184 executable,
174185 library,
186+ diagnose,
175187 } => {
176188 prove_command (
177- file, prover, timeout, neural, executable, library, & formatter,
189+ file, prover, timeout, neural, executable, library, diagnose , & formatter,
178190 )
179191 . await ?;
180192 } ,
@@ -185,8 +197,9 @@ async fn main() -> Result<()> {
185197 timeout,
186198 executable,
187199 library,
200+ diagnose,
188201 } => {
189- verify_command ( file, prover, timeout, executable, library, & formatter) . await ?;
202+ verify_command ( file, prover, timeout, executable, library, diagnose , & formatter) . await ?;
190203 } ,
191204
192205 Commands :: Search {
@@ -246,40 +259,29 @@ async fn prove_command(
246259 neural : bool ,
247260 executable : Option < PathBuf > ,
248261 library : Vec < PathBuf > ,
262+ diagnose : bool ,
249263 formatter : & OutputFormatter ,
250264) -> Result < ( ) > {
251265 info ! ( "Starting proof for: {}" , file. display( ) ) ;
252266
253- // Detect or use specified prover
254267 let kind = detect_prover ( prover_kind, & file) ?;
255-
256- // Create prover configuration
257268 let config = create_config ( kind, timeout, neural, executable, library) ?;
258-
259- // Create prover backend
260269 let prover = echidna:: provers:: ProverFactory :: create ( kind, config)
261270 . context ( "Failed to create prover backend" ) ?;
262271
263- // Show progress
264272 let pb = create_progress_bar ( "Parsing proof file..." ) ;
265-
266- // Parse the proof file
267273 let state = prover
268274 . parse_file ( file. clone ( ) )
269275 . await
270276 . context ( "Failed to parse proof file" ) ?;
271277
272278 pb. set_message ( "Verifying proof..." ) ;
273-
274- // Verify the proof
275279 let result = prover
276280 . verify_proof ( & state)
277281 . await
278282 . context ( "Failed to verify proof" ) ?;
279-
280283 pb. finish_and_clear ( ) ;
281284
282- // Output result
283285 if result {
284286 formatter. success ( & format ! (
285287 "✓ Proof verified successfully for {}" ,
@@ -292,57 +294,70 @@ async fn prove_command(
292294 file. display( )
293295 ) ) ?;
294296 formatter. output_proof_state ( & state) ?;
297+ if diagnose {
298+ emit_diagnostic ( kind, & * prover, & state, formatter) . await ;
299+ }
295300 std:: process:: exit ( 1 ) ;
296301 }
297302
298303 Ok ( ( ) )
299304}
300305
306+ /// Run `check()` on the prover and display a structured diagnostic report.
307+ ///
308+ /// Called after a failed `verify_proof()` when `--diagnose` is active.
309+ /// Uses the richer `ProverOutcome` returned by `check()` to produce an
310+ /// actionable report via `diagnose_from_outcome`.
311+ async fn emit_diagnostic (
312+ kind : ProverKind ,
313+ prover : & dyn ProverBackend ,
314+ state : & echidna:: core:: ProofState ,
315+ formatter : & OutputFormatter ,
316+ ) {
317+ let outcome = match prover. check ( state) . await {
318+ Ok ( o) => o,
319+ Err ( e) => {
320+ let _ = formatter. error ( & format ! ( "[diagnose] could not run check(): {}" , e) ) ;
321+ return ;
322+ } ,
323+ } ;
324+ let report = diagnose_from_outcome ( kind, & outcome) ;
325+ let _ = formatter. info ( "\n --- Proof Failure Diagnostic ---" ) ;
326+ let _ = formatter. info ( & report. display ( ) ) ;
327+ }
328+
301329/// Verify command implementation
302330async fn verify_command (
303331 file : PathBuf ,
304332 prover_kind : Option < ProverKind > ,
305333 timeout : u64 ,
306334 executable : Option < PathBuf > ,
307335 library : Vec < PathBuf > ,
336+ diagnose : bool ,
308337 formatter : & OutputFormatter ,
309338) -> Result < ( ) > {
310339 info ! ( "Verifying proof: {}" , file. display( ) ) ;
311340
312- // Detect or use specified prover
313341 let kind = detect_prover ( prover_kind, & file) ?;
314-
315- // Create prover configuration
316342 let config = create_config ( kind, timeout, true , executable, library) ?;
317-
318- // Create prover backend
319343 let prover = echidna:: provers:: ProverFactory :: create ( kind, config)
320344 . context ( "Failed to create prover backend" ) ?;
321345
322- // Show progress
323346 let pb = create_progress_bar ( "Parsing proof file..." ) ;
324-
325- // Parse the proof file
326347 let state = prover
327348 . parse_file ( file. clone ( ) )
328349 . await
329350 . context ( "Failed to parse proof file" ) ?;
330351
331352 pb. set_message ( "Verifying proof..." ) ;
332-
333- // Verify the proof
334353 let result = prover
335354 . verify_proof ( & state)
336355 . await
337356 . context ( "Failed to verify proof" ) ?;
338-
339357 pb. finish_and_clear ( ) ;
340358
341- // Output result
342359 if result {
343360 formatter. success ( & format ! ( "✓ Proof is valid: {}" , file. display( ) ) ) ?;
344-
345- // Show proof statistics
346361 formatter. info ( & format ! ( "Goals: {}" , state. goals. len( ) ) ) ?;
347362 formatter. info ( & format ! ( "Tactics: {}" , state. proof_script. len( ) ) ) ?;
348363 formatter. info ( & format ! (
@@ -351,6 +366,9 @@ async fn verify_command(
351366 ) ) ?;
352367 } else {
353368 formatter. error ( & format ! ( "✗ Proof is invalid: {}" , file. display( ) ) ) ?;
369+ if diagnose {
370+ emit_diagnostic ( kind, & * prover, & state, formatter) . await ;
371+ }
354372 std:: process:: exit ( 1 ) ;
355373 }
356374
0 commit comments