Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 106 additions & 2 deletions madara/crates/primitives/receipt/src/revert_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@
/// Rules:
/// - Always keep VM tracebacks that belong to LibraryCall entries
/// - For CallContract entries:
/// - Keep the traceback if the next entry is a LibraryCall or if it's the last entry
/// - Remove the traceback if the next entry is another CallContract
/// - Keep if followed by a LibraryCall or if it's the last CallContract before error
/// - Keep if the next CallContract is the last one before error (preserve call chain context)
/// - Remove if followed by a CallContract that has more CallContracts after it
/// - If no owning entry point is found, keep the traceback (safety default)
fn should_keep_vm_traceback(error_stack: &ErrorStack, vm_index: usize) -> bool {
let owning_entry = find_parent_entry_point(error_stack, vm_index);
Expand All @@ -76,7 +77,9 @@
true
} else {
// For CallContract entries, check what comes next
// Keep if no nested CallContract, OR if the next CallContract is the last one
!has_nested_call_contract_after(error_stack, vm_index)
|| is_next_call_contract_last(error_stack, vm_index)
}
}
// If we can't find an owning entry, keep the traceback
Expand Down Expand Up @@ -200,6 +203,38 @@
false
}

/// Checks if the next CallContract after this VM traceback is the last one before the error.
/// Returns true only if:
/// 1. The next EntryPoint is a CallContract
/// 2. There are no more EntryPoints after it (just error messages)
///
/// This specifically handles the case where CallContract chain ends in error without LibraryCall.
fn is_next_call_contract_last(error_stack: &ErrorStack, vm_index: usize) -> bool {
let mut found_next_entry = false;

// Scan forward to find EntryPoints
for segment in error_stack.stack.iter().skip(vm_index + 1) {
if let ErrorStackSegment::EntryPoint(entry_point) = segment {
if !found_next_entry {
// This is the next entry point
if entry_point.preamble_type != PreambleType::CallContract {
// Next entry is not a CallContract, so doesn't apply
return false;
}
found_next_entry = true;
} else {
// Found a second entry point after the next CallContract
// If there's another EntryPoint (CallContract or LibraryCall), return false
// We only want to keep both when the chain ends without more EntryPoints
return false;
}
}
}

// If we found the next CallContract and no more EntryPoints after it, it's the last
found_next_entry
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -451,4 +486,73 @@

assert_eq!(result, expected);
}

#[test]

Check warning on line 490 in madara/crates/primitives/receipt/src/revert_error.rs

View workflow job for this annotation

GitHub Actions / lint-rust / cargo-lint

Diff in /home/runner/_work/madara/madara/madara/crates/primitives/receipt/src/revert_error.rs
fn test_format_for_receipt_filters_redundant_tracebacks_3() {
// Build the ErrorStack structure that represents the unfiltered error
let mut error_stack = ErrorStack {
header: ErrorStackHeader::Execution,
stack: vec![],
};

// Entry 0: CallContract with VM traceback (should be kept - last before error)
error_stack.push(
EntryPointErrorFrame {

Check warning on line 500 in madara/crates/primitives/receipt/src/revert_error.rs

View workflow job for this annotation

GitHub Actions / lint-rust / cargo-lint

Diff in /home/runner/_work/madara/madara/madara/crates/primitives/receipt/src/revert_error.rs
depth: 0,
preamble_type: PreambleType::CallContract,
storage_address: test_contract_address!("0x01f062c02ee674cc7a88dd94e0b230b76decf76aff55b83ec32a90936e7569ab"),
class_hash: test_class_hash!("0x073414441639dcd11d1846f287650a00c60c416b9d3ba45d31c651672125b2c2"),
selector: Some(EntryPointSelector(test_felt!("0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad"))),
}
.into(),
);
error_stack.push(
VmExceptionFrame {
pc: Relocatable { segment_index: 0, offset: 35988 },
error_attr_value: None,
traceback: Some("Cairo traceback (most recent call last):\nUnknown location (pc=0:330)\nUnknown location (pc=0:11695)\n".to_string()),
}
.into(),
);

// Entry 1: CallContract with VM traceback (should be kept - last before error)
error_stack.push(
EntryPointErrorFrame {

Check warning on line 520 in madara/crates/primitives/receipt/src/revert_error.rs

View workflow job for this annotation

GitHub Actions / lint-rust / cargo-lint

Diff in /home/runner/_work/madara/madara/madara/crates/primitives/receipt/src/revert_error.rs
depth: 1,
preamble_type: PreambleType::CallContract,
storage_address: test_contract_address!("0x02953d14869a4f634e02272ac288713dc514bfd018857569252b74f4a96e91fc"),
class_hash: test_class_hash!("0x05e4b69d808cd273b7d84ea27f1954c1eb8b61211036d293b1a0d5e9f34726e8"),
selector: Some(EntryPointSelector(test_felt!("0x00aceca4cf913a062eea8c1609ce381630d82808d51e757d7b2b68c961933fa8"))),
}
.into(),
);
error_stack.push(
VmExceptionFrame {
pc: Relocatable { segment_index: 0, offset: 117929 },
error_attr_value: None,
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()),
}
.into(),
);

Check warning on line 536 in madara/crates/primitives/receipt/src/revert_error.rs

View workflow job for this annotation

GitHub Actions / lint-rust / cargo-lint

Diff in /home/runner/_work/madara/madara/madara/crates/primitives/receipt/src/revert_error.rs

// Final error message
error_stack.push(
ErrorStackSegment::StringFrame("Exceeded the maximum number of events, number events: 1001, max number events: 1000.".to_string()),
);

let revert_error = RevertError::Execution(error_stack);

// Verify that the RevertError structure produces the correct input (unfiltered)
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.";
assert_eq!(revert_error.to_string(), input);

// Expected output: all tracebacks kept (entry 0 before LibraryCall, entry 1 belongs to LibraryCall, entry 2 before LibraryCall)
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.";

let result = revert_error.to_string();

Check warning on line 553 in madara/crates/primitives/receipt/src/revert_error.rs

View workflow job for this annotation

GitHub Actions / lint-rust / cargo-lint

Diff in /home/runner/_work/madara/madara/madara/crates/primitives/receipt/src/revert_error.rs
assert_eq!(result, expected);
}


}
Loading