@@ -262,6 +262,20 @@ pub enum ExecutionError {
262262 /// The actual number of deferred proofs that were verified.
263263 actual : usize ,
264264 } ,
265+
266+ /// Insufficient deferred proofs were provided.
267+ #[ error( "insufficient deferred proofs: unable to verify proof at index {index}" ) ]
268+ InsufficientDeferredProofs {
269+ /// The index of the proof that was requested.
270+ index : usize ,
271+ } ,
272+
273+ /// Deferred proof verification failed.
274+ #[ error( "deferred proof verification failed: {reason}" ) ]
275+ DeferredProofVerificationFailed {
276+ /// The reason for the verification failure.
277+ reason : String ,
278+ } ,
265279}
266280
267281impl < ' a > Executor < ' a > {
@@ -1623,7 +1637,51 @@ impl<'a> Executor<'a> {
16231637 // Executing a syscall optionally returns a value to write to the t0
16241638 // register. If it returns None, we just keep the
16251639 // syscall_id in t0.
1626- let res = syscall_impl. execute ( & mut precompile_rt, syscall, b, c) ;
1640+ let res = if syscall == SyscallCode :: VERIFY_SP1_PROOF {
1641+ // Catch panics for VERIFY_SP1_PROOF to provide better error messages.
1642+ match std:: panic:: catch_unwind ( std:: panic:: AssertUnwindSafe ( || {
1643+ syscall_impl. execute ( & mut precompile_rt, syscall, b, c)
1644+ } ) ) {
1645+ Ok ( result) => result,
1646+ Err ( panic_payload) => {
1647+ // Extract the panic message.
1648+ let msg = panic_payload
1649+ . downcast_ref :: < String > ( )
1650+ . map ( String :: as_str)
1651+ . or_else ( || panic_payload. downcast_ref :: < & str > ( ) . copied ( ) ) ;
1652+
1653+ if let Some ( msg) = msg {
1654+ let index = precompile_rt. rt . state . proof_stream_ptr ;
1655+ let available = precompile_rt. rt . state . proof_stream . len ( ) ;
1656+
1657+ if msg. contains ( "Not enough proofs" ) {
1658+ tracing:: error!(
1659+ "Insufficient deferred proofs: unable to verify proof \
1660+ at index {index} because only {available} proofs were \
1661+ provided. \
1662+ Make sure you're passing the correct number of proofs \
1663+ and that you're calling verify_sp1_proof for all proofs."
1664+ ) ;
1665+ return Err ( ExecutionError :: InsufficientDeferredProofs {
1666+ index,
1667+ } ) ;
1668+ } else if msg. contains ( "Failed to verify proof" ) {
1669+ tracing:: error!(
1670+ "Failed to verify deferred proof at index {index}."
1671+ ) ;
1672+ return Err ( ExecutionError :: DeferredProofVerificationFailed {
1673+ reason : msg. to_string ( ) ,
1674+ } ) ;
1675+ }
1676+ }
1677+
1678+ // Resume default behavior for unknown panics.
1679+ std:: panic:: resume_unwind ( panic_payload) ;
1680+ }
1681+ }
1682+ } else {
1683+ syscall_impl. execute ( & mut precompile_rt, syscall, b, c)
1684+ } ;
16271685 let a = if let Some ( val) = res { val } else { syscall_id } ;
16281686
16291687 // If the syscall is `HALT` and the exit code is non-zero, return an error.
@@ -2137,8 +2195,9 @@ impl<'a> Executor<'a> {
21372195 if self . state . proof_stream_ptr != self . state . proof_stream . len ( ) {
21382196 tracing:: error!(
21392197 "Not all proofs were verified. \
2140- Make sure you are passing the correct number of proofs \
2141- and that you are calling verify_sp1_proof for all proofs."
2198+ Expected to verify {expected} proofs, but only {actual} were verified. \
2199+ Make sure you're passing the correct number of proofs \
2200+ and that you're calling verify_sp1_proof for all proofs."
21422201 ) ;
21432202 return Err ( ExecutionError :: UnverifiedDeferredProofs {
21442203 expected : self . state . proof_stream . len ( ) ,
0 commit comments