fix: check for diff before cow#20
Conversation
WalkthroughAdded early-exit guards to multiple Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Caller
participant AccountSharedData
Caller->>AccountSharedData: mutation_method(new_value)
Note over AccountSharedData: Compare new_value with current_value
alt values equal
AccountSharedData-->>Caller: return (no-op)
else values differ
rect rgb(230, 248, 255)
AccountSharedData->>AccountSharedData: perform copy-on-write (if Borrowed)
AccountSharedData->>AccountSharedData: update internal state / mutate data
end
AccountSharedData-->>Caller: return (updated)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/lib.rs(6 hunks)
🔇 Additional comments (8)
src/lib.rs (8)
304-306: LGTM - Efficient early exit for unchanged lamports.The equality check correctly prevents unnecessary COW operations when the lamports value is already set to the desired value.
335-337: LGTM - Efficient guard for unchanged owner bytes.The comparison correctly checks if the owner's byte array already matches the source, avoiding unnecessary COW and copy operations.
348-355: LGTM - Proper early exit with maintained safety.The executable flag check correctly prevents unnecessary COW operations, and the
unsafeblock is properly scoped around thecow()call.
683-696: LGTM - Consistent optimization across both account variants.Both
OwnedandBorrowedvariants now properly check if the delegated flag already has the desired value before performing mutations, avoiding unnecessary work.
710-724: LGTM - Consistent flag optimization pattern.The compressed flag optimization follows the same correct pattern as other flag setters, preventing unnecessary mutations when the value is unchanged.
737-751: LGTM - Consistent flag setter optimization.The undelegating flag setter correctly implements the early-exit pattern used across all flag setters in this PR.
869-871: LGTM - Appropriate optimization for data mutation.The equality check prevents unnecessary COW operations when data is unchanged. While the slice comparison has O(n) cost, it's still more efficient than COW + copy when the data is actually the same, which aligns with this PR's goal of avoiding unnecessary modifications.
924-926: LGTM - Consistent data comparison optimization.The early exit when data is unchanged follows the same pattern as
set_data_from_sliceand correctly prevents unnecessary COW operations.
| if *acc.owner == owner { | ||
| return; | ||
| } | ||
| acc.cow(); | ||
| acc.owner_changed = *acc.owner != owner; | ||
| *acc.owner = owner; |
There was a problem hiding this comment.
🧩 Analysis chain
Verify the impact of early return on owner_changed flag.
The early return at lines 321-323 prevents updating the owner_changed flag at line 325. If owner_changed was previously true and set_owner is called with the current owner value, the flag will remain true instead of being set to false. Confirm whether this behavior is intentional or if the flag should be explicitly cleared when the owner matches.
Run the following script to examine how owner_changed is used:
🏁 Script executed:
#!/bin/bash
# Search for usages of owner_changed to understand its semantics
rg -nP -C5 'owner_changed' --type rustLength of output: 2699
🏁 Script executed:
#!/bin/bash
# Find all places where owner_changed is READ or CHECKED (not just assigned)
rg -nP 'owner_changed\s*[!=|&]|if.*owner_changed|match.*owner_changed|\borner_changed\s*[,\)]' --type rust -C3Length of output: 336
🏁 Script executed:
#!/bin/bash
# Search for serialization or validation logic that might use owner_changed
rg -nP '(serialize|write|persist|validate|check)' --type rust -C2 | grep -A10 -B10 'owner_changed'Length of output: 0
🏁 Script executed:
#!/bin/bash
# Simple grep for all owner_changed references to ensure nothing missed
grep -rn 'owner_changed' src/ --include='*.rs' | head -30Length of output: 299
🏁 Script executed:
#!/bin/bash
# Check if owner_changed is part of public API or exported fields
rg -nP 'pub.*owner_changed|owner_changed.*pub' --type rust -B2 -A2Length of output: 305
🏁 Script executed:
#!/bin/bash
# Search for any conditional logic or pattern matching that might read the flag
rg -nP '\\.owner_changed' --type rust -C4Length of output: 0
Fix early return logic to properly clear the owner_changed flag.
The early return at lines 321-323 prevents updating owner_changed at line 325. This leaves the flag in an inconsistent state: if set_owner is called with the current owner value when the flag was previously true, it remains true instead of being cleared to false. This violates the flag's semantic meaning ("has the owner been changed") and creates a state inconsistency.
Move the owner_changed assignment before the early return or update it within the early return branch:
if *acc.owner == owner {
acc.owner_changed = false; // Explicitly clear when owner is unchanged
return;
}
acc.cow();
acc.owner_changed = true; // Simplified since we only reach here when changed
*acc.owner = owner;🤖 Prompt for AI Agents
In src/lib.rs around lines 321 to 326, the early return when the new owner
equals the current owner prevents updating the owner_changed flag, leaving it
stale; update the logic so owner_changed is cleared when owner is unchanged and
set when changed—either set acc.owner_changed = false inside the early-return
branch before returning, or move the owner_changed assignment before the return
and set it to the appropriate boolean, then proceed with acc.cow() and assigning
*acc.owner = owner only when changed.
This avoids having the
is_dirtyflag set when no actual changes were applied.This is critical to check that a non-delegated account was not touched.
Summary by CodeRabbit