Skip to content

Propagate cleanup boundary error in get_block#1121

Open
nikolaysamoil0ff wants to merge 2 commits intomagicblock-labs:masterfrom
nikolaysamoil0ff:get_block
Open

Propagate cleanup boundary error in get_block#1121
nikolaysamoil0ff wants to merge 2 commits intomagicblock-labs:masterfrom
nikolaysamoil0ff:get_block

Conversation

@nikolaysamoil0ff
Copy link
Copy Markdown

@nikolaysamoil0ff nikolaysamoil0ff commented Mar 31, 2026

Summary

get_block() currently ignores the result of check_lowest_cleanup_slot(slot):

let _lock = self.check_lowest_cleanup_slot(slot);

If the requested slot has already been cleaned up, the error is silently dropped and the method continues reading from storage. This can lead to returning partial or inconsistent block data past the cleanup boundary.

The cleanup check is intended to enforce a strict boundary, so failures should be propagated instead of ignored.

This change uses ? to return the error early, ensuring predictable behavior and preventing invalid reads beyond the cleanup range.

Compatibility

  • No breaking changes
  • Config change (describe):
  • Migration needed (describe):

Testing

  • tests (or explain)

Checklist

  • docs updated (if needed)
  • closes #

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling when accessing cleaned-up ledger blocks so failures are reported and block reads are aborted instead of continuing.
    • Prevented panics during transaction metadata decoding by returning a clear conversion error when metadata is invalid.

get_block() currently ignores the result of check_lowest_cleanup_slot(slot):
```rust
let _lock = self.check_lowest_cleanup_slot(slot);
```

If the requested slot has already been cleaned up, the error is silently dropped and the method continues reading from storage. This can lead to returning partial or inconsistent block data past the cleanup boundary.

The cleanup check is intended to enforce a strict boundary, so failures should be propagated instead of ignored.

This change uses `?` to return the error early, ensuring predictable behavior and preventing invalid reads beyond the cleanup range.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

📝 Walkthrough

Walkthrough

The change updates error handling in magicblock-ledger/src/store/api.rs. In Ledger::get_block, check_lowest_cleanup_slot(slot) now propagates errors (?) so failures (e.g., SlotCleanedUp) are returned immediately. Also, conversion of TransactionStatusMeta no longer uses unwrap(); it uses try_from(...) with map_err(...) to return a LedgerError::TransactionConversionError on failure and uses the converted meta on success. No public API declarations were changed.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
magicblock-ledger/src/store/api.rs (2)

425-428: ⚠️ Potential issue | 🟠 Major

Replace panic-prone metadata conversion with fallible error propagation.

On Line 427, .unwrap() can panic in production if status meta conversion fails; this should return a LedgerError instead.

Proposed fix
-                    Ok(VersionedTransactionWithStatusMeta {
-                        transaction,
-                        meta: TransactionStatusMeta::try_from(meta).unwrap(),
-                    })
+                    let meta = TransactionStatusMeta::try_from(meta).map_err(|e| {
+                        LedgerError::TransactionConversionError(
+                            format!(
+                                "failed to convert transaction status meta at slot {}: {}",
+                                slot, e
+                            ),
+                        )
+                    })?;
+                    Ok(VersionedTransactionWithStatusMeta {
+                        transaction,
+                        meta,
+                    })

As per coding guidelines "Treat any usage of .unwrap() or .expect() in production Rust code as a MAJOR issue."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@magicblock-ledger/src/store/api.rs` around lines 425 - 428, The code
currently uses TransactionStatusMeta::try_from(meta).unwrap() when constructing
VersionedTransactionWithStatusMeta, which can panic; replace the unwrap with
fallible error propagation by mapping the conversion error into the function's
LedgerError result (e.g., using map_err or ? to convert into an appropriate
LedgerError variant) and return Err(LedgerError::...) from the surrounding
function instead of unwrapping, so the metadata conversion failure is reported
as a LedgerError rather than causing a panic.

384-431: 🧹 Nitpick | 🔵 Trivial

Add a regression test for get_block on cleaned slots.

Given this behavioral change, add a unit test that sets lowest_cleanup_slot >= slot and asserts get_block(slot) returns Err(LedgerError::SlotCleanedUp) rather than Ok(Some(_))/Ok(None).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@magicblock-ledger/src/store/api.rs` around lines 384 - 431, Add a unit test
for get_block that reproduces the cleaned-up-slot behavior by setting the
store's lowest cleanup slot to be >= the target slot and asserting
get_block(slot) returns Err(LedgerError::SlotCleanedUp); to implement, create a
test that initializes the relevant store state, calls the helper that sets
lowest_cleanup_slot (or directly manipulates the value checked by
check_lowest_cleanup_slot), then call get_block(slot) and assert it returns the
SlotCleanedUp error rather than Ok(Some(_))/Ok(None); reference the get_block
method and the check_lowest_cleanup_slot helper and assert against
LedgerError::SlotCleanedUp.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@magicblock-ledger/src/store/api.rs`:
- Around line 425-428: The code currently uses
TransactionStatusMeta::try_from(meta).unwrap() when constructing
VersionedTransactionWithStatusMeta, which can panic; replace the unwrap with
fallible error propagation by mapping the conversion error into the function's
LedgerError result (e.g., using map_err or ? to convert into an appropriate
LedgerError variant) and return Err(LedgerError::...) from the surrounding
function instead of unwrapping, so the metadata conversion failure is reported
as a LedgerError rather than causing a panic.
- Around line 384-431: Add a unit test for get_block that reproduces the
cleaned-up-slot behavior by setting the store's lowest cleanup slot to be >= the
target slot and asserting get_block(slot) returns
Err(LedgerError::SlotCleanedUp); to implement, create a test that initializes
the relevant store state, calls the helper that sets lowest_cleanup_slot (or
directly manipulates the value checked by check_lowest_cleanup_slot), then call
get_block(slot) and assert it returns the SlotCleanedUp error rather than
Ok(Some(_))/Ok(None); reference the get_block method and the
check_lowest_cleanup_slot helper and assert against LedgerError::SlotCleanedUp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a4645d85-c683-4387-bdfb-01e936733a6b

📥 Commits

Reviewing files that changed from the base of the PR and between 0599539 and 2ab337d.

📒 Files selected for processing (1)
  • magicblock-ledger/src/store/api.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
magicblock-ledger/src/store/api.rs (1)

1077-1084: ⚠️ Potential issue | 🟠 Major

Inconsistent error handling: same .unwrap() pattern exists here.

This code has the same issue that was fixed in get_block at lines 425-432. The status.try_into().unwrap() can panic if the protobuf conversion fails. For consistency with the fix in this PR, this should use the same map_err pattern.

🔧 Proposed fix for consistency
 result = self
     .transaction_status_cf
     .get_protobuf((signature, slot))?
     .map(|status| {
-        let status = status.try_into().unwrap();
-        (slot, status)
+        TransactionStatusMeta::try_from(status).map(|meta| (slot, meta))
+    })
+    .transpose()
+    .map_err(|e| {
+        LedgerError::TransactionConversionError(format!(
+            "failed to convert transaction status meta at slot {}: {}",
+            slot, e
+        ))
     });

As per coding guidelines: {magicblock-*,programs,storage-proto}/**: Treat any usage of .unwrap() or .expect() in production Rust code as a MAJOR issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@magicblock-ledger/src/store/api.rs` around lines 1077 - 1084, The code calls
status.try_into().unwrap() inside the closure returned from
transaction_status_cf.get_protobuf((signature, slot)), which can panic; update
the closure to propagate the conversion error instead of unwrapping—use
try_into() and convert its Err into the same StorageError used in the get_block
fix (i.e., replace the unwrap with a map_err/from conversion so the closure
returns Result<(Slot, Status), StorageError> and works with the surrounding ?
operator), referencing transaction_status_cf.get_protobuf, the closure that maps
status, and the try_into conversion to mirror the error-handling pattern used in
get_block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@magicblock-ledger/src/store/api.rs`:
- Around line 1077-1084: The code calls status.try_into().unwrap() inside the
closure returned from transaction_status_cf.get_protobuf((signature, slot)),
which can panic; update the closure to propagate the conversion error instead of
unwrapping—use try_into() and convert its Err into the same StorageError used in
the get_block fix (i.e., replace the unwrap with a map_err/from conversion so
the closure returns Result<(Slot, Status), StorageError> and works with the
surrounding ? operator), referencing transaction_status_cf.get_protobuf, the
closure that maps status, and the try_into conversion to mirror the
error-handling pattern used in get_block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a6467400-fa82-4605-9b82-dc3e662aeaa5

📥 Commits

Reviewing files that changed from the base of the PR and between 2ab337d and c9fc633.

📒 Files selected for processing (1)
  • magicblock-ledger/src/store/api.rs

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.

1 participant