@@ -63,8 +63,9 @@ impl RevertErrorExt for RevertError {
6363/// Rules:
6464/// - Always keep VM tracebacks that belong to LibraryCall entries
6565/// - For CallContract entries:
66- /// - Keep the traceback if the next entry is a LibraryCall or if it's the last entry
67- /// - Remove the traceback if the next entry is another CallContract
66+ /// - Keep if followed by a LibraryCall or if it's the last CallContract before error
67+ /// - Keep if the next CallContract is the last one before error (preserve call chain context)
68+ /// - Remove if followed by a CallContract that has more CallContracts after it
6869/// - If no owning entry point is found, keep the traceback (safety default)
6970fn should_keep_vm_traceback ( error_stack : & ErrorStack , vm_index : usize ) -> bool {
7071 let owning_entry = find_parent_entry_point ( error_stack, vm_index) ;
@@ -76,7 +77,9 @@ fn should_keep_vm_traceback(error_stack: &ErrorStack, vm_index: usize) -> bool {
7677 true
7778 } else {
7879 // For CallContract entries, check what comes next
80+ // Keep if no nested CallContract, OR if the next CallContract is the last one
7981 !has_nested_call_contract_after ( error_stack, vm_index)
82+ || is_next_call_contract_last ( error_stack, vm_index)
8083 }
8184 }
8285 // If we can't find an owning entry, keep the traceback
@@ -203,6 +206,37 @@ fn has_nested_call_contract_after(error_stack: &ErrorStack, vm_index: usize) ->
203206 false
204207}
205208
209+ /// Checks if the next CallContract after this VM traceback is the last one before the error.
210+ /// Returns true only if:
211+ /// 1. The next EntryPoint is a CallContract
212+ /// 2. There are no more EntryPoints after it (just error messages)
213+ /// This specifically handles the case where CallContract chain ends in error without LibraryCall.
214+ fn is_next_call_contract_last ( error_stack : & ErrorStack , vm_index : usize ) -> bool {
215+ let mut found_next_entry = false ;
216+
217+ // Scan forward to find EntryPoints
218+ for segment in error_stack. stack . iter ( ) . skip ( vm_index + 1 ) {
219+ if let ErrorStackSegment :: EntryPoint ( entry_point) = segment {
220+ if !found_next_entry {
221+ // This is the next entry point
222+ if entry_point. preamble_type != PreambleType :: CallContract {
223+ // Next entry is not a CallContract, so doesn't apply
224+ return false ;
225+ }
226+ found_next_entry = true ;
227+ } else {
228+ // Found a second entry point after the next CallContract
229+ // If there's another EntryPoint (CallContract or LibraryCall), return false
230+ // We only want to keep both when the chain ends without more EntryPoints
231+ return false ;
232+ }
233+ }
234+ }
235+
236+ // If we found the next CallContract and no more EntryPoints after it, it's the last
237+ found_next_entry
238+ }
239+
206240#[ cfg( test) ]
207241mod tests {
208242 use super :: * ;
@@ -428,4 +462,73 @@ mod tests {
428462
429463 assert_eq ! ( result, expected) ;
430464 }
465+
466+ #[ test]
467+ fn test_format_for_receipt_filters_redundant_tracebacks_3 ( ) {
468+ // Build the ErrorStack structure that represents the unfiltered error
469+ let mut error_stack = ErrorStack {
470+ header : ErrorStackHeader :: Execution ,
471+ stack : vec ! [ ] ,
472+ } ;
473+
474+ // Entry 0: CallContract with VM traceback (should be kept - last before error)
475+ error_stack. push (
476+ EntryPointErrorFrame {
477+ depth : 0 ,
478+ preamble_type : PreambleType :: CallContract ,
479+ storage_address : test_contract_address ! ( "0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab" ) ,
480+ class_hash : test_class_hash ! ( "0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2" ) ,
481+ selector : Some ( EntryPointSelector ( test_felt ! ( "0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" ) ) ) ,
482+ }
483+ . into ( ) ,
484+ ) ;
485+ error_stack. push (
486+ VmExceptionFrame {
487+ pc : Relocatable { segment_index : 0 , offset : 35988 } ,
488+ error_attr_value : None ,
489+ traceback : Some ( "Cairo traceback (most recent call last):\n Unknown location (pc=0:330)\n Unknown location (pc=0:11695)\n " . to_string ( ) ) ,
490+ }
491+ . into ( ) ,
492+ ) ;
493+
494+ // Entry 1: CallContract with VM traceback (should be kept - last before error)
495+ error_stack. push (
496+ EntryPointErrorFrame {
497+ depth : 1 ,
498+ preamble_type : PreambleType :: CallContract ,
499+ storage_address : test_contract_address ! ( "0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc" ) ,
500+ class_hash : test_class_hash ! ( "0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8" ) ,
501+ selector : Some ( EntryPointSelector ( test_felt ! ( "0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8" ) ) ) ,
502+ }
503+ . into ( ) ,
504+ ) ;
505+ error_stack. push (
506+ VmExceptionFrame {
507+ pc : Relocatable { segment_index : 0 , offset : 117929 } ,
508+ error_attr_value : None ,
509+ traceback : Some ( "Cairo traceback (most recent call last):\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n " . to_string ( ) ) ,
510+ }
511+ . into ( ) ,
512+ ) ;
513+
514+ // Final error message
515+ error_stack. push (
516+ ErrorStackSegment :: StringFrame ( "Exceeded the maximum number of events, number events: 1001, max number events: 1000." . to_string ( ) ) ,
517+ ) ;
518+
519+ let revert_error = RevertError :: Execution ( error_stack) ;
520+
521+ // Verify that the RevertError structure produces the correct input (unfiltered)
522+ let input = "Transaction execution has failed:\n 0: Error in the called contract (contract address: 0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab, class hash: 0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\n Error at pc=0:35988:\n Cairo traceback (most recent call last):\n Unknown location (pc=0:330)\n Unknown location (pc=0:11695)\n \n 1: Error in the called contract (contract address: 0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc, class hash: 0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8, selector: 0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8):\n Error at pc=0:117929:\n Cairo traceback (most recent call last):\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n \n Exceeded the maximum number of events, number events: 1001, max number events: 1000." ;
523+ assert_eq ! ( revert_error. to_string( ) , input) ;
524+
525+ // Expected output: all tracebacks kept (entry 0 before LibraryCall, entry 1 belongs to LibraryCall, entry 2 before LibraryCall)
526+ let expected = "Transaction execution has failed:\n 0: Error in the called contract (contract address: 0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab, class hash: 0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\n Error at pc=0:35988:\n Cairo traceback (most recent call last):\n Unknown location (pc=0:330)\n Unknown location (pc=0:11695)\n \n 1: Error in the called contract (contract address: 0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc, class hash: 0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8, selector: 0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8):\n Error at pc=0:117929:\n Cairo traceback (most recent call last):\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n Unknown location (pc=0:118178)\n \n Exceeded the maximum number of events, number events: 1001, max number events: 1000." ;
527+
528+ let result = revert_error. to_string ( ) ;
529+
530+ assert_eq ! ( result, expected) ;
531+ }
532+
533+
431534}
0 commit comments