Skip to content

Commit 62d8aa1

Browse files
committed
Test3 for Chain Reverts
1 parent 2afde45 commit 62d8aa1

File tree

1 file changed

+105
-2
lines changed

1 file changed

+105
-2
lines changed

madara/crates/primitives/receipt/src/revert_error.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
6970
fn 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)]
207241
mod 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):\nUnknown location (pc=0:330)\nUnknown 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):\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown 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:\n0: Error in the called contract (contract address: 0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab, class hash: 0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\nError at pc=0:35988:\nCairo traceback (most recent call last):\nUnknown location (pc=0:330)\nUnknown location (pc=0:11695)\n\n1: Error in the called contract (contract address: 0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc, class hash: 0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8, selector: 0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8):\nError at pc=0:117929:\nCairo traceback (most recent call last):\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\n\nExceeded 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:\n0: Error in the called contract (contract address: 0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab, class hash: 0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\nError at pc=0:35988:\nCairo traceback (most recent call last):\nUnknown location (pc=0:330)\nUnknown location (pc=0:11695)\n\n1: Error in the called contract (contract address: 0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc, class hash: 0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8, selector: 0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8):\nError at pc=0:117929:\nCairo traceback (most recent call last):\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\nUnknown location (pc=0:118178)\n\nExceeded 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

Comments
 (0)