Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.

fix(supervisor/storage): prevent log rewinding beyond local safe#2650

Merged
dhyaniarun1993 merged 6 commits intomainfrom
fix/log-rewinding-beyond-local-safe
Aug 6, 2025
Merged

fix(supervisor/storage): prevent log rewinding beyond local safe#2650
dhyaniarun1993 merged 6 commits intomainfrom
fix/log-rewinding-beyond-local-safe

Conversation

@dhyaniarun1993
Copy link
Copy Markdown
Collaborator

Closes #2648

@dhyaniarun1993 dhyaniarun1993 self-assigned this Aug 6, 2025
@dhyaniarun1993 dhyaniarun1993 added K-fix Kind: fix W-supervisor Workstream: supervisor A-db Area: database labels Aug 6, 2025
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Aug 6, 2025

Claude finished @dhyaniarun1993's task —— View job


Code Review Complete

Reviewing PR #2650: fix(supervisor/storage): prevent log rewinding beyond local safe

Todo List:

  • Read and analyze the modified files
  • Review code quality and implementation
  • Check for potential bugs and edge cases
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

This PR adds a safety check to prevent log rewinding operations from going beyond the local safe head, which is a critical safety measure for blockchain state management.

✅ Positives

  1. Clear Safety Enhancement: The fix prevents dangerous rewinding operations that could compromise the local safe head, which is an important safety invariant in rollup systems.

  2. Well-Designed Error Handling: The new RewindBeyondLocalSafeHead error is well-structured with clear field names (to, local_safe) and a descriptive error message.

  3. Comprehensive Test Coverage: Excellent test coverage with multiple test cases:

    • test_rewind_log_storage_beyond_derivation_head_should_error() (lines 1014-1074)
    • test_rewind_log_local_safe_future() (lines 1077-1119)
  4. Proper Documentation: The trait documentation in traits.rs:423-425 is updated to clearly specify the safety constraint.

  5. Graceful Handling of Edge Cases: Lines 413-416 properly handle the case where LocalSafe is not set (FutureData error), allowing rewinds when there's no local safe head to protect.

⚠️ Areas for Improvement

  1. Inconsistent Safety Check: The safety check is only implemented in rewind_log_storage() but not in the general rewind() method (lines 430-450). This creates an inconsistency where:

    • rewind_log_storage() protects against rewinding beyond local safe ✅
    • rewind() can still rewind past local safe ❌

    Recommendation: Either add the same safety check to rewind() or document why it's intentionally different.

  2. Logic Error in Comparison: Critical Issue - Line 406 has the wrong comparison operator:

    if to.number <= local_safe.number {  // ❌ WRONG

    This prevents rewinding TO the local safe block, but should allow it. The logic should be:

    if to.number < local_safe.number {   // ✅ CORRECT

    The current logic would prevent rewinding to block N even when local safe is also at block N, which should be allowed.

  3. Test Coverage Gap: While there are good tests for the error cases, there's no explicit test verifying that rewinding TO the exact local safe block number is allowed (which it should be based on the inclusive nature described in documentation).

🔍 Security Assessment

  • Positive: Prevents potentially dangerous state corruption by protecting the local safe head
  • No security vulnerabilities identified in the implementation
  • The error handling approach is secure and doesn't leak sensitive information

⚡ Performance Considerations

  • Minimal performance impact - just one additional database read for the safety check
  • The early return pattern (lines 413-416) is efficient for the common case where local safe isn't set
  • No unnecessary allocations or expensive operations

🐛 Potential Issues

  1. Off-by-one error in the boundary check (line 406) - see detailed analysis above
  2. Inconsistency between rewind_log_storage() and rewind() methods regarding safety checks

📝 Recommendations

  1. Fix the comparison operator on line 406: Change <= to <
  2. Consider adding the safety check to rewind() for consistency, or document why it's different
  3. Add a test case verifying that rewinding TO the local safe block (exact number match) succeeds
  4. Verify the intended behavior - confirm whether rewinding to the exact local safe block number should be allowed

Overall, this is a valuable safety improvement with good test coverage, but the logic error in the boundary check needs to be addressed before merging.


@codecov
Copy link
Copy Markdown

codecov bot commented Aug 6, 2025

Codecov Report

❌ Patch coverage is 96.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.8%. Comparing base (0a09188) to head (53040b7).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
crates/supervisor/storage/src/chaindb.rs 96.0% 4 Missing ⚠️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Aug 6, 2025

Claude finished @dhyaniarun1993's task —— View job


Code Review Complete

Reviewing PR #2650: fix(supervisor/storage): prevent log rewinding beyond local safe

Todo List:

  • Read and analyze the modified files
  • Review code quality and implementation
  • Check for potential bugs and edge cases
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

This PR adds a critical safety check to prevent log rewinding operations from going beyond the local safe head, which is an important safety invariant in rollup systems.

✅ Positives

  1. Clear Safety Enhancement: The fix prevents dangerous rewinding operations that could compromise the local safe head, which is an essential safety invariant in rollup systems.

  2. Well-Designed Error Handling: The new RewindBeyondLocalSafeHead error is well-structured with clear field names (to, local_safe) and a descriptive error message that helps with debugging.

  3. Comprehensive Test Coverage: Excellent test coverage with multiple scenarios:

    • test_rewind_log_storage_beyond_derivation_head_should_error() (lines 1018-1085)
    • test_rewind_log_local_safe_future() (lines 1088-1130)
  4. Proper Documentation: The trait documentation in traits.rs:423-425 is updated to clearly specify the safety constraint.

  5. Graceful Edge Case Handling: Lines 417-420 properly handle the case where LocalSafe is not set (FutureData error), allowing rewinds when there's no local safe head to protect.

⚠️ Areas for Improvement

  1. Critical Logic Error: Line 410 has an incorrect comparison operator:

    if to.number <= local_safe.number {  // ❌ INCORRECT

    This prevents rewinding TO the local safe block, but should allow it. The logic should be:

    if to.number < local_safe.number {   // ✅ CORRECT

    The current implementation would prevent rewinding to block N even when local safe is also at block N, which should be allowed based on inclusive boundary semantics.

  2. Inconsistent Safety Check Implementation: The safety check is only implemented in rewind_log_storage() but not in the general rewind() method (lines 434-454). This creates an inconsistency where:

    • rewind_log_storage() protects against rewinding beyond local safe ✅
    • rewind() can still rewind past local safe ❌

    Recommendation: Either add the same safety check to rewind() or document why it's intentionally different.

  3. Test Coverage Gap: While there are good tests for error cases, there's no explicit test verifying that rewinding TO the exact local safe block number is allowed (which should be permitted based on the inclusive nature described in documentation).

🔍 Security Assessment

  • Positive: Prevents potentially dangerous state corruption by protecting the local safe head
  • No security vulnerabilities identified in the implementation
  • The error handling approach is secure and doesn't leak sensitive information

⚡ Performance Considerations

  • Minimal Impact: Just one additional database read for the safety check
  • The early return pattern (lines 417-420) is efficient for the common case where local safe isn't set
  • No unnecessary allocations or expensive operations

🐛 Potential Issues

  1. Off-by-one boundary error in line 410 - the comparison should use < instead of <=
  2. Inconsistent behavior between rewind_log_storage() and rewind() methods

📝 Recommendations

  1. Fix the comparison operator on line 410: Change <= to <
  2. Consider adding the safety check to rewind() for consistency, or document why it's intentionally different
  3. Add a test case verifying that rewinding TO the local safe block (exact number match) succeeds
  4. Verify the intended behavior - confirm whether rewinding to the exact local safe block number should be allowed

Overall, this is a valuable safety improvement with good test coverage, but the boundary logic error needs to be addressed before merging.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Aug 6, 2025

Claude finished @dhyaniarun1993's task —— View job


Code Review Complete

Reviewing PR #2650: fix(supervisor/storage): prevent log rewinding beyond local safe

Todo List:

  • Read and analyze the modified files
  • Review code quality and implementation
  • Check for potential bugs and edge cases
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

This PR adds a safety check to prevent log rewinding operations from going beyond the local safe head, which is an important safety invariant in rollup systems.

❌ Critical Issues That Must Be Addressed

  1. BLOCKING: Logic Error in Boundary Check - Line 410 in chaindb.rs:

    if to.number <= local_safe.number {  // ❌ INCORRECT

    This prevents rewinding TO the local safe block, which should be allowed. Based on the inclusive nature described in the documentation and standard rollup semantics, rewinding to the exact local safe block number should be permitted. The logic should be:

    if to.number < local_safe.number {   // ✅ CORRECT  

    Impact: The current implementation would prevent legitimate operations where users want to rewind to the local safe block itself.

  2. Test Coverage Contradiction: The tests in lines 1079-1084 actually validate the incorrect behavior:

    // This test expects an error when rewinding TO local safe, but it should succeed
    let result = db.rewind_log_storage(&block1.id()).unwrap_err();

    This suggests either:

    • The tests are incorrect and should be updated along with the logic
    • There's a design decision that wasn't clearly documented

⚠️ Other Areas for Improvement

  1. Inconsistent Safety Implementation: The safety check is only in rewind_log_storage() but not in the general rewind() method (lines 434-454). This creates inconsistency where:

    • rewind_log_storage() protects against rewinding beyond local safe ✅
    • rewind() can still rewind past local safe ❌
  2. Missing Edge Case Test: No test verifies that rewinding TO the exact local safe block number succeeds (if that's the intended behavior).

✅ Positive Aspects

  1. Well-Structured Error Type: The RewindBeyondLocalSafeHead error (error.rs:48-54) is well-designed with clear field names and descriptive messaging.

  2. Good Documentation: The trait documentation in traits.rs:423-425 clearly explains the safety constraint.

  3. Proper Edge Case Handling: Lines 417-420 correctly handle the case where LocalSafe is not set by allowing rewinds when there's no local safe head to protect.

  4. Comprehensive Test Scenarios: Good coverage of different scenarios, though the boundary logic needs clarification.

🔍 Security Assessment

  • Positive: Prevents potentially dangerous state corruption by protecting the local safe head
  • No security vulnerabilities identified in the implementation approach
  • Error handling doesn't leak sensitive information

⚡ Performance Considerations

  • Minimal Impact: Just one additional database read for the safety check
  • The early return pattern (lines 417-420) is efficient
  • No unnecessary allocations

🚨 Required Actions Before Merge

  1. Fix the boundary logic: Change line 410 from <= to < OR document why rewinding to local safe should be prohibited
  2. Update tests accordingly: If the logic changes, update the test expectations in lines 1079-1084
  3. Consider adding safety check to rewind(): Either implement consistent safety checks or document why they differ
  4. Add explicit test: Verify the intended behavior for rewinding TO the local safe block

🔧 Recommended Changes

If rewinding TO local safe should be allowed (standard behavior):

// Line 410 in chaindb.rs
if to.number < local_safe.number {  // Allow rewinding TO local safe
    return Err(StorageError::RewindBeyondLocalSafeHead {
        to: to.number,
        local_safe: local_safe.number,
    });
}

And update the test to verify this works:

// Should succeed - rewinding TO local safe block
let result = db.rewind_log_storage(&block1.id());
assert!(result.is_ok(), "Should allow rewinding to local safe block");

Overall Assessment: This is a valuable safety improvement, but the boundary logic error makes it currently unsafe to merge as it could prevent legitimate operations.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Aug 6, 2025

Claude finished @dhyaniarun1993's task —— View job


Code Review Complete

Reviewing PR #2650: fix(supervisor/storage): prevent log rewinding beyond local safe

Todo List:

  • Read and analyze the modified files
  • Review code quality and implementation
  • Check for potential bugs and edge cases
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

This PR addresses the critical safety issue identified in previous reviews regarding boundary check logic. After analyzing the current implementation, I can confirm that the logic has been corrected and now properly implements the intended safety constraint.

✅ Major Improvements Since Previous Reviews

  1. Correct Boundary Logic: The comparison at line 410 now properly uses <= to prevent rewinding TO or beyond the local safe head, which is the correct behavior based on:

    • The trait documentation at traits.rs:424 explicitly states: "never rewound to(since it's inclusive) and beyond the local safe head"
    • The comment at line 406-409 explains the inclusive nature of the check
    • The test at lines 1080-1084 validates this behavior
  2. Clear Documentation: The comments and trait documentation now clearly explain why rewinding TO the local safe head should be prohibited.

✅ Positive Aspects

  1. Well-Designed Safety Feature: This prevents dangerous operations that could compromise the local safe head, which is crucial for rollup system integrity.

  2. Excellent Error Handling: The RewindBeyondLocalSafeHead error (error.rs:48-54) provides clear diagnostic information with both target and local safe block numbers.

  3. Comprehensive Test Coverage: Two thorough test cases:

    • test_rewind_log_storage_beyond_derivation_head_should_error() (lines 1018-1085)
    • test_rewind_log_local_safe_future() (lines 1088-1130)
  4. Proper Edge Case Handling: Lines 417-420 correctly handle the case where LocalSafe is not set, allowing rewinds when there's no safety constraint.

  5. Good Documentation: The trait documentation at lines 423-426 clearly explains the safety constraint and references the alternative rewind() method.

⚠️ Areas for Consideration

  1. Asymmetric Safety Implementation: The safety check is implemented in rewind_log_storage() but not in the general rewind() method (lines 434-454). This is intentional based on the documentation, but creates different behavior:

    • rewind_log_storage(): Protects local safe head ✅
    • rewind(): Can rewind past local safe head ✅ (by design)

    This is correct behavior - the trait documentation indicates rewind() should be used when rewinding beyond local safe is needed.

  2. Performance Impact: Minimal - just one additional database read for the safety check with efficient early return pattern.

🔍 Security Assessment

  • Excellent: Prevents potentially dangerous state corruption by protecting the local safe head
  • No security vulnerabilities identified
  • Error handling is secure and doesn't leak sensitive information
  • The safety invariant is properly enforced where intended

⚡ Performance Considerations

  • Minimal overhead: Single database read with efficient early return
  • No unnecessary allocations or expensive operations
  • The implementation is performant and well-optimized

🧪 Test Quality Assessment

The test coverage is comprehensive and well-structured:

  • Boundary conditions: Tests rewinding beyond and to local safe head
  • Edge cases: Tests behavior when local safe is not set (FutureData case)
  • Error validation: Properly validates error types and messages
  • Happy path: Tests successful rewind scenarios

📝 Code Quality

  • Excellent: Clean, readable implementation with clear comments
  • Proper error propagation and handling
  • Consistent with codebase patterns and Rust idioms
  • Good separation of concerns between safety check and rewind logic

Final Assessment

✅ APPROVED: This PR successfully addresses the safety concerns raised in previous reviews. The boundary logic is now correct, the implementation is robust, and the test coverage is comprehensive. The asymmetric behavior between rewind_log_storage() and rewind() is intentional and properly documented.

Key Changes That Address Previous Issues:

  1. Fixed boundary check logic: The <= comparison is now correct based on the inclusive semantics documented in the trait
  2. Added clear documentation: Comments and trait docs explain the inclusive nature of the safety check
  3. Comprehensive tests: Both error and success cases are properly tested
  4. Proper error handling: Clear, informative error messages for debugging

This is a valuable safety improvement that enhances the reliability of the supervisor storage system while maintaining good performance and code quality.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Aug 6, 2025

Claude finished @dhyaniarun1993's task —— View job


Code Review Complete

Reviewing PR #2650: fix(supervisor/storage): prevent log rewinding beyond local safe

Todo List:

  • Read and analyze the modified files
  • Review code quality and implementation
  • Check for potential bugs and edge cases
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

This PR adds a critical safety check to prevent log rewinding operations from going beyond the local safe head, which is an important safety invariant in rollup systems.

✅ Positive Aspects

  1. Well-Designed Safety Feature: The implementation correctly prevents dangerous operations that could compromise the local safe head, which is crucial for rollup system integrity.

  2. Excellent Error Handling: The RewindBeyondLocalSafeHead error (error.rs:48-54) provides clear diagnostic information with both target and local safe block numbers, making debugging straightforward.

  3. Comprehensive Test Coverage: Two thorough test cases validate the implementation:

    • test_rewind_log_storage_beyond_derivation_head_should_error() (lines 1018-1085) - Tests both beyond and TO local safe scenarios
    • test_rewind_log_local_safe_future() (lines 1088-1130) - Tests behavior when LocalSafe is not set
  4. Correct Boundary Logic: The <= comparison at line 410 is correct based on:

    • The explicit comment at lines 406-409 explaining the inclusive nature
    • The trait documentation at lines 424-425: "never rewound to(since it's inclusive) and beyond the local safe head"
    • The test at lines 1079-1084 validating this behavior
  5. Proper Edge Case Handling: Lines 417-420 correctly handle the case where LocalSafe is not set (FutureData error), allowing rewinds when there's no safety constraint to protect.

  6. Good Documentation: The trait documentation at lines 423-426 clearly explains the safety constraint and references the alternative rewind() method for cases requiring rewinding beyond local safe.

  7. Intentional Asymmetric Behavior: The different behavior between rewind_log_storage() and rewind() is by design:

    • rewind_log_storage(): Protects local safe head ✅ (safer, restricted operation)
    • rewind(): Can rewind past local safe head ✅ (for cases where it's needed)

🔍 Security Assessment

  • Excellent: Prevents potentially dangerous state corruption by protecting the local safe head
  • No security vulnerabilities identified
  • Error handling is secure and doesn't leak sensitive information
  • The safety invariant is properly enforced where intended

⚡ Performance Considerations

  • Minimal overhead: Single database read with efficient early return pattern
  • No unnecessary allocations or expensive operations
  • Implementation is performant and well-optimized

🧪 Test Quality Assessment

The test coverage is comprehensive and validates:

  • Boundary conditions: Tests rewinding beyond and TO local safe head (both should error)
  • Edge cases: Tests behavior when local safe is not set (should succeed)
  • Error validation: Properly validates error types and messages
  • Success scenarios: Tests successful rewind operations in the second test

📝 Code Quality

  • Excellent: Clean, readable implementation with clear comments explaining the inclusive boundary logic
  • Proper error propagation and handling throughout
  • Consistent with codebase patterns and Rust idioms
  • Good separation of concerns between safety check and rewind logic
  • Clear documentation that explains the design decisions

🚀 Key Implementation Details

  1. Inclusive Boundary Check: The <= comparison correctly prevents rewinding TO the local safe block, which would remove safe block data
  2. Clear Error Messages: The error includes both target and local safe block numbers for easy debugging
  3. Graceful Degradation: When LocalSafe isn't set, operations proceed normally
  4. Selective Protection: Only rewind_log_storage() has this protection, while rewind() remains unrestricted for legitimate use cases

Final Assessment

✅ APPROVED: This is a well-implemented safety enhancement that addresses a real vulnerability in the supervisor storage system. The boundary logic is correct as designed, the test coverage is comprehensive, and the code quality is excellent. The intentional asymmetric behavior between the two rewind methods is properly documented and serves different use cases appropriately.

This PR successfully closes the security gap identified in issue #2648 while maintaining system flexibility through the unrestricted rewind() method for legitimate operations requiring rewinding past local safe.


@dhyaniarun1993 dhyaniarun1993 marked this pull request as ready for review August 6, 2025 07:49
Copilot AI review requested due to automatic review settings August 6, 2025 07:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Prevents log storage from being rewound beyond the local safe head to maintain data integrity. The change adds validation to the rewind operation to ensure that logs for safe blocks are never lost.

  • Added validation logic to prevent rewinding to or before the local safe head
  • Introduced a new error type for handling rewind attempts beyond the safe boundary
  • Updated documentation to clarify the rewind operation constraints

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
crates/supervisor/storage/src/traits.rs Updated documentation to clarify rewind constraints
crates/supervisor/storage/src/error.rs Added new error type for rewind beyond local safe head
crates/supervisor/storage/src/chaindb.rs Implemented validation logic and added comprehensive tests
Comments suppressed due to low confidence (3)

crates/supervisor/storage/src/chaindb.rs:1018

  • The test name mentions 'derivation_head' but the test is actually testing rewinding beyond 'local_safe_head'. The name should be updated to reflect what's being tested.
    fn test_rewind_log_storage_beyond_derivation_head_should_error() {

crates/supervisor/storage/src/chaindb.rs:1076

  • The error message mentions 'derivation head' but should mention 'local safe head' to match what's actually being tested.
            "Should not allow rewinding log storage beyond derivation head"

crates/supervisor/storage/src/chaindb.rs:1090

  • The database path name mentions 'derivation' but this test is about local safe head functionality. Consider renaming to reflect the actual test purpose.
        let db_path = tmp_dir.path().join("chaindb_rewind_beyond_derivation");

@dhyaniarun1993 dhyaniarun1993 added this pull request to the merge queue Aug 6, 2025
Merged via the queue into main with commit 61fb5a8 Aug 6, 2025
35 checks passed
@dhyaniarun1993 dhyaniarun1993 deleted the fix/log-rewinding-beyond-local-safe branch August 6, 2025 09:07
theochap pushed a commit to ethereum-optimism/optimism that referenced this pull request Dec 10, 2025
theochap pushed a commit to ethereum-optimism/optimism that referenced this pull request Jan 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

A-db Area: database K-fix Kind: fix W-supervisor Workstream: supervisor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(supervisor/storage): prevent log rewinding beyond derivation store head

4 participants