Skip to content

fix: debug trace bridge call matching#1605

Merged
arnaubennassar merged 1 commit intodevelopfrom
fix/debug_trace
Apr 29, 2026
Merged

fix: debug trace bridge call matching#1605
arnaubennassar merged 1 commit intodevelopfrom
fix/debug_trace

Conversation

@arnaubennassar
Copy link
Copy Markdown
Collaborator

🔄 Changes Summary

  • Filter debug trace call matching to actual CALL frames in bridgesync and claimsync, avoiding calldata extraction from DELEGATECALL, STATICCALL, CALLCODE, or missing-type frames.
  • Add call tracer frame type constants and include the type field in decoded trace calls.
  • Make claim calldata extraction reject ambiguous distinct matching bridge calls while accepting duplicate identical matches.
  • Extend bridge and claim sync tests for call-frame filtering, ambiguous calldata, and updated mocked debug traces.

⚠️ Breaking Changes

  • 🛠️ Config: None
  • 🔌 API/CLI: None
  • 🗑️ Deprecated Features: None

📋 Config Updates

  • 🧾 Diff/Config snippet: None

✅ Testing

  • 🤖 Automatic: go test ./bridgesync ./claimsync
  • 🖱️ Manual: Not run

🐞 Issues

  • None

🔗 Related PRs

  • None

📝 Notes

  • The fix keeps debug trace traversal behavior but only treats canonical CALL frames to the bridge as extraction candidates, preventing delegate-call calldata from being selected as if it were a direct bridge call.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 29, 2026

Claude finished @arnaubennassar's task in 1m 38s —— View job


Code Review Complete ✓


🚀 What's New

This PR fixes debug trace call matching in bridgesync and claimsync by filtering only CALL frame types and rejecting ambiguous claim calldata extraction when multiple distinct matching bridge calls exist.

🐛 Bug Fixes

  • Call frame filtering: Only CALL frames to the bridge are now considered for calldata extraction, preventing DELEGATECALL, STATICCALL, CALLCODE, or missing-type frames from being incorrectly treated as direct bridge calls
  • Ambiguous calldata rejection: Claims with multiple distinct matching bridge calls now properly error out instead of silently using the wrong calldata

📋 Config Updates

None

⚠️ Breaking Changes

None


Review Feedback

🟢 Overall Assessment

This is a well-implemented security fix with excellent test coverage. The changes correctly address the core issue of distinguishing between different call frame types in debug traces.

✅ Strengths

  1. Security Fix - Properly filters call frame types to prevent delegate call exploitation
  2. Comprehensive Testing - Excellent test coverage including edge cases for:
    • Non-CALL frame types (DELEGATECALL, STATICCALL, CALLCODE)
    • Reverted calls
    • Ambiguous calldata scenarios
    • Duplicate identical calls vs distinct calls
  3. Clear Constants - Well-defined call type constants improve code readability
  4. Consistent Implementation - Same pattern applied to both bridgesync and claimsync
  5. DeepEqual for Duplicates - Using reflect.DeepEqual is appropriate for detecting true duplicates

🟡 Suggestions (Code Quality)

1. Code Duplication: Call Type Constants

Location: bridgesync/downloader.go:67-81, claimsync/downloader.go:69-83

The call type constants are duplicated across both packages. Consider extracting to a shared package.

Suggestion:

// In aggkit/types/calltracer.go or similar
package types

const (
    CallTypeCall = "CALL"
    CallTypeDelegateCall = "DELEGATECALL"
    CallTypeStaticCall = "STATICCALL"
    CallTypeCallCode = "CALLCODE"
    CallTypeCreate = "CREATE"
    CallTypeCreate2 = "CREATE2"
    CallTypeSelfDestruct = "SELFDESTRUCT"
)

Then import in both packages. This follows DRY principle and ensures consistency.

2. Error Message Clarity

Location: claimsync/downloader.go:566-567

The error message "ambiguous claim calldata" could be more descriptive about why this is problematic.

Current:

return fmt.Errorf("ambiguous claim calldata for globalIndex %s: found %d matching bridge calls",
    c.GlobalIndex.String(), len(candidates))

Suggested:

return fmt.Errorf("ambiguous claim calldata for globalIndex %s: found %d distinct matching bridge calls (expected 1 unique match)",
    c.GlobalIndex.String(), len(candidates))

3. Performance: DeepEqual Usage

Location: claimsync/downloader.go:575-581

Using reflect.DeepEqual in a loop is acceptable for this use case (small candidate lists), but worth noting:

  • reflect.DeepEqual compares all fields including private ones
  • For Claim structs with pointers (*big.Int), this correctly handles value comparison
  • Performance is fine since candidate lists are typically small (1-3 items)

No change needed, but consider documenting this design choice if candidate lists could grow large in the future.

4. Missing Type Check Test in bridgesync

Location: bridgesync/downloader_test.go

The claimsync package has a dedicated test TestFindCallSkipsNonCallFrameTypes (lines 80-106 in claimsync/downloader_test.go), but bridgesync doesn't have an equivalent isolated test for this filtering behavior.

Suggestion: Add a similar test to bridgesync/downloader_test.go:

func TestFindCallSkipsNonCallFrameTypes(t *testing.T) {
    // Test that DELEGATECALL, STATICCALL, etc. are skipped
    // Similar to claimsync/downloader_test.go:80-106
}

🟢 What's Done Well

  1. Test Organization - The test file structure is excellent:

    • TestFindCall - Basic functionality
    • TestFindCallSkipsNonCallFrameTypes - Frame type filtering
    • TestFindCallWithMixedMethods - Method filtering
    • TestSetClaimCalldataFromRootFiltersDelegateCall - Integration testing
  2. Edge Case Coverage - Tests cover:

    • Reverted calls (properly skipped)
    • Empty candidate lists (error returned)
    • Duplicate identical calls (accepted)
    • Distinct ambiguous calls (rejected)
  3. Security Awareness - The PR correctly identifies the security risk of accepting delegate call calldata as if it were a direct bridge call

  4. Code Style - Follows Go best practices:

    • Proper error wrapping with context
    • Clear constant naming
    • Descriptive test names
    • Uses require (not assert) in tests ✓

🔴 Critical Issues

None found. This PR is production-ready.


Additional Notes

Why This Fix Matters

When a transaction uses DELEGATECALL to invoke the bridge contract, the calldata might differ from what would be used in a direct CALL. By only considering CALL frames, this PR ensures:

  1. Correct calldata extraction - Only direct bridge calls provide authoritative calldata
  2. Security - Prevents malicious delegate calls from injecting misleading calldata
  3. Correctness - Ambiguous scenarios (multiple distinct calls) are now detected and rejected

Test Coverage Analysis

The PR adds 181 new lines to claimsync/downloader_test.go, covering:

  • Frame type filtering (lines 80-106)
  • Mixed method calls (lines 108-160)
  • Unrecognized methods (lines 162-204)
  • Delegate call filtering (lines 293-428)
  • Ambiguous vs duplicate scenarios (lines 413-427)

This represents excellent test coverage for the fix.


Summary

Approve with suggestions - The core fix is correct and well-tested. The suggestions above are minor code quality improvements that don't block merging.

Priority of suggestions:

@arnaubennassar arnaubennassar self-assigned this Apr 29, 2026
@arnaubennassar arnaubennassar changed the title Fix debug trace bridge call matching fix: debug trace bridge call matching Apr 29, 2026
@sonarqubecloud
Copy link
Copy Markdown

@arnaubennassar arnaubennassar merged commit 5e75ba1 into develop Apr 29, 2026
25 of 27 checks passed
@arnaubennassar arnaubennassar deleted the fix/debug_trace branch April 29, 2026 09:09
arnaubennassar added a commit that referenced this pull request Apr 29, 2026
## 🔄 Changes Summary
- Backports `5e75ba1a` (`fix: debug trace bridge call matching (#1605)`)
to `release/0.8`.
- Filters debug trace matching to actual `CALL` frames in `bridgesync`,
avoiding calldata extraction from `DELEGATECALL`, `STATICCALL`,
`CALLCODE`, or missing-type frames.
- Adds call tracer frame type constants and includes the `type` field in
decoded trace calls.
- Updates the applicable `bridgesync` tests for call-frame filtering and
mocked debug traces.

## ⚠️ Breaking Changes
- 🛠️ **Config**: None
- 🔌 **API/CLI**: None
- 🗑️ **Deprecated Features**: None

## 📋 Config Updates
- 🧾 **Diff/Config snippet**: None

## ✅ Testing
- 🤖 **Automatic**: `go test ./bridgesync -run
'TestFindCall|TestBackfillTxnSender|TestClaimCalldata' -count=1`\n- 🤖
**Automatic**: `go test ./bridgesync` was also run, but failed on the
`release/0.8` branch after a long package run; the relevant touched
tests above passed.\n- 🖱️ **Manual**: Not run\n\n## 🐞 Issues\n-
None\n\n## 🔗 Related PRs\n- Backport of #1605\n\n## 📝 Notes\n-
`claimsync` changes from the original squash commit are not present in
this backport because `release/0.8` does not contain the `claimsync`
downloader files changed by #1605.
arnaubennassar added a commit that referenced this pull request Apr 29, 2026
## 🔄 Changes Summary
- Backports `5e75ba1a` (`fix: debug trace bridge call matching (#1605)`)
to `release/0.10`.
- Filters debug trace matching to actual `CALL` frames in `bridgesync`
and `claimsync`, avoiding calldata extraction from `DELEGATECALL`,
`STATICCALL`, `CALLCODE`, or missing-type frames.
- Adds call tracer frame type constants and includes the `type` field in
decoded trace calls.
- Makes claim calldata extraction reject ambiguous distinct matching
bridge calls while accepting duplicate identical matches.
- Extends bridge and claim sync tests for call-frame filtering,
ambiguous calldata, and mocked debug traces.

## ⚠️ Breaking Changes
- 🛠️ **Config**: None
- 🔌 **API/CLI**: None
- 🗑️ **Deprecated Features**: None

## 📋 Config Updates
- 🧾 **Diff/Config snippet**: None

## ✅ Testing
- 🤖 **Automatic**: `go test ./bridgesync ./claimsync`
- 🖱️ **Manual**: Not run

## 🐞 Issues
- None

## 🔗 Related PRs
- Backport of #1605

## 📝 Notes
- Cherry-pick applied cleanly on `release/0.10`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants