Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: replace panic with error return #740

Merged
merged 1 commit into from
Oct 14, 2024
Merged

refactor: replace panic with error return #740

merged 1 commit into from
Oct 14, 2024

Conversation

zakir-code
Copy link
Contributor

@zakir-code zakir-code commented Oct 13, 2024

Summary by CodeRabbit

  • New Features

    • Enhanced error handling across various methods for improved clarity and stability.
    • Updated validation checks in message types for better data integrity.
  • Bug Fixes

    • Improved error propagation in critical methods to prevent unexpected panics.
  • Documentation

    • Minor adjustments made to logging and comments for better understanding.
  • Tests

    • Updated test cases to ensure proper error handling is validated.

Copy link

coderabbitai bot commented Oct 13, 2024

Walkthrough

The pull request introduces significant modifications to the error handling mechanisms within the Keeper struct and associated methods across several files. Key changes include the introduction of error return types in multiple methods, replacing panic calls with error returns, and enhancing error propagation. Additionally, there are updates to method signatures and improvements in logging and comments for clarity. The overall structure and logic of some functions remain unchanged, while others have been streamlined for better error management.

Changes

File Path Change Summary
x/crosschain/keeper/abci.go Modified Keeper methods for improved error handling; updated signatures for cleanupTimedOutBatches and cleanupTimeOutBridgeCall to return errors.
x/crosschain/keeper/attestation.go Enhanced error handling in Attest and TryAttestation; updated TryAttestation to return an error.
x/crosschain/keeper/attestation_handler.go Modified AttestationHandler and ExecuteClaim for direct error propagation; logic simplified.
x/crosschain/keeper/genesis.go Updated InitGenesis to use MustUnpackAttestationClaim for direct unpacking, eliminating error handling.
x/crosschain/keeper/oracle_set.go Changed UpdateOracleSetExecuted to return an error instead of panicking.
x/crosschain/keeper/outgoing_tx.go Updated OutgoingTxBatchExecuted to include error return; changed handling of unknown batch nonce to return an error instead of panicking.
x/crosschain/keeper/pending_execute_claim.go Enhanced error handling in SavePendingExecuteClaim and GetPendingExecuteClaim; updated return types to include errors.
x/crosschain/keeper/pending_execute_claim_test.go Updated TestKeeper_SavePendingExecuteClaim to check for errors from SavePendingExecuteClaim and GetPendingExecuteClaim.
x/crosschain/types/msgs.go Renamed UnpackAttestationClaim to MustUnpackAttestationClaim and changed its return type; updated ExternalClaim interface and ValidateBasic methods for additional checks.

Possibly related PRs

🐰 In the meadow where bunnies play,
Errors now clear, they won't lead us astray.
With methods refined, and panic's defeat,
Our code is now tidy, oh what a treat!
Hops of joy echo, as we celebrate,
For error handling's strong, we can now elevate! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (6)
x/crosschain/keeper/pending_execute_claim_test.go (1)

53-54: Improved error handling for GetPendingExecuteClaim

The changes here are consistent with the PR objective and the previous modification. The GetPendingExecuteClaim method now returns both a claim and an error, which are properly handled in the test case. This approach follows Go best practices for error handling.

Consider swapping the order of the assertions for better readability:

s.Require().NoError(err)
s.Require().Equal(tt.claim, claim)

This way, we first ensure there's no error before comparing the claims, which is a more logical order of operations.

x/crosschain/keeper/genesis.go (1)

Line range hint 1-180: Summary: Reconsider error handling strategy in InitGenesis

The changes in this file replace error-checking unpacking with MustUnpackAttestationClaim, which can lead to panics. This seems to contradict the PR's objective of "replace panic with error return". Consider the following recommendations:

  1. Revert to the previous error-checking approach for unpacking attestations.
  2. If simplification is desired, implement a custom error handling mechanism that logs errors and continues initialization, rather than panicking.
  3. Add validation for attestations earlier in the genesis import process to ensure all attestations are valid before unpacking.

These changes will align better with the PR's objective and improve the robustness of the genesis initialization process.

x/crosschain/keeper/oracle_set.go (1)

Line range hint 1-34: Approve changes with a minor suggestion for improvement

The modification successfully replaces the panic with an error return, which aligns with the PR objective and allows for more graceful error handling. This change is consistent with Go's error handling conventions and doesn't introduce any new logic errors.

To further improve the code, consider wrapping the error returned from the Equal method to provide more context:

- return err
+ return types.ErrInvalid.Wrap(err)

This will maintain consistency with the error wrapping used earlier in the function and provide more context about the nature of the error.

x/crosschain/keeper/abci.go (2)

163-173: Approve changes with a minor suggestion for error logging

The modifications to cleanupTimedOutBatches align well with the PR objective of replacing panics with error returns. The error handling is implemented correctly, and the function now properly returns an error.

To further improve error handling and debugging:

func (k Keeper) cleanupTimedOutBatches(ctx sdk.Context) error {
    externalBlockHeight := k.GetLastObservedBlockHeight(ctx).ExternalBlockHeight
    k.IterateOutgoingTxBatches(ctx, func(batch *types.OutgoingTxBatch) bool {
        if batch.BatchTimeout < externalBlockHeight {
            if err := k.RefundOutgoingTxBatch(ctx, batch.TokenContract, batch.BatchNonce); err != nil {
                k.Logger(ctx).Error("failed to refund outgoing tx batch", "error", err)
                return true
            }
        }
        return false
    })
    return nil
}

This change adds error logging, which can be helpful for debugging issues in production environments.


176-191: Approve changes with a minor suggestion for error logging

The modifications to cleanupTimeOutBridgeCall are in line with the PR objective of replacing panics with error returns. The error handling is implemented correctly, and the function now properly returns an error.

To further improve error handling and debugging:

func (k Keeper) cleanupTimeOutBridgeCall(ctx sdk.Context) error {
    externalBlockHeight := k.GetLastObservedBlockHeight(ctx).ExternalBlockHeight
    k.IterateOutgoingBridgeCalls(ctx, func(data *types.OutgoingBridgeCall) bool {
        if data.Timeout > externalBlockHeight {
            return true
        }
        if err := k.RefundOutgoingBridgeCall(ctx, data); err != nil {
            k.Logger(ctx).Error("failed to refund outgoing bridge call", "error", err, "nonce", data.Nonce)
            return true
        }
        k.DeleteOutgoingBridgeCallRecord(ctx, data.Nonce)
        return false
    })
    return nil
}

This change adds error logging, which can be helpful for debugging issues in production environments. It also includes the nonce in the error log for easier tracing.

x/crosschain/keeper/pending_execute_claim.go (1)

18-18: Consider returning nil explicitly

At the end of SavePendingExecuteClaim, the err should be nil if no error occurred. Returning nil explicitly enhances code clarity.

Apply the following diff to improve readability:

-	return err
+	return nil
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8c8d540 and d4430ad.

📒 Files selected for processing (9)
  • x/crosschain/keeper/abci.go (2 hunks)
  • x/crosschain/keeper/attestation.go (5 hunks)
  • x/crosschain/keeper/attestation_handler.go (2 hunks)
  • x/crosschain/keeper/genesis.go (2 hunks)
  • x/crosschain/keeper/oracle_set.go (1 hunks)
  • x/crosschain/keeper/outgoing_tx.go (2 hunks)
  • x/crosschain/keeper/pending_execute_claim.go (1 hunks)
  • x/crosschain/keeper/pending_execute_claim_test.go (1 hunks)
  • x/crosschain/types/msgs.go (1 hunks)
🧰 Additional context used
🔇 Additional comments (24)
x/crosschain/keeper/pending_execute_claim_test.go (2)

50-51: Improved error handling for SavePendingExecuteClaim

The changes here align well with the PR objective of replacing panic with error returns. The SavePendingExecuteClaim method now returns an error, which is properly checked in the test case. This approach follows Go best practices for error handling and makes the code more robust.


50-54: Overall improvement in error handling

The changes in this file significantly improve the error handling in the TestKeeper_SavePendingExecuteClaim function. By updating both SavePendingExecuteClaim and GetPendingExecuteClaim to return errors and properly checking these errors in the test cases, the code now follows Go best practices more closely.

These modifications align well with the PR objective of replacing panic with error returns. They enhance the robustness of the test cases and provide more explicit error handling, which will make debugging easier if issues arise in the future.

The functionality of the tests remains intact, with the added benefit of more comprehensive error checking. This update contributes to the overall quality and reliability of the codebase.

x/crosschain/keeper/genesis.go (1)

95-95: ⚠️ Potential issue

Caution: Potential panic introduced with MustUnpackAttestationClaim

The change from UnpackAttestationClaim to MustUnpackAttestationClaim simplifies the code by removing explicit error handling. However, this introduces a potential panic if the unpacking fails. Consider the following:

  1. Is it guaranteed that all attestations in the genesis state are valid?
  2. How would a panic at this point affect the node's ability to start up?

Consider keeping the previous error-checking approach or wrapping this call in a recovery mechanism to handle potential panics gracefully.

To verify the safety of this change, let's check for any validation of attestations before this point:

x/crosschain/keeper/oracle_set.go (1)

Line range hint 1-34: Verify impact on callers of UpdateOracleSetExecuted

The change in the UpdateOracleSetExecuted function signature (now returning an error) is correct and aligns with the PR objective. However, it's crucial to ensure that all callers of this function are updated to handle the new error return.

Please run the following script to identify and verify all callers of UpdateOracleSetExecuted:

Please review the output to ensure all callers properly handle the returned error. Update any callers that don't handle the error appropriately.

✅ Verification successful

Callers Handle Error from UpdateOracleSetExecuted Properly

Verified that all callers of UpdateOracleSetExecuted appropriately handle the returned error.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all callers of UpdateOracleSetExecuted and verify they handle the new error return

# Search for function calls to UpdateOracleSetExecuted
echo "Searching for UpdateOracleSetExecuted callers:"
rg --type go "UpdateOracleSetExecuted\(" -A 5

# Search for method calls on Keeper struct
echo "\nSearching for Keeper.UpdateOracleSetExecuted callers:"
rg --type go "\w+\.UpdateOracleSetExecuted\(" -A 5

Length of output: 1575

x/crosschain/keeper/abci.go (1)

Line range hint 1-291: Overall assessment: Changes align well with PR objectives

The modifications in this file successfully replace panic calls with error returns in the cleanupTimedOutBatches and cleanupTimeOutBridgeCall functions. These changes improve error handling and align with the PR's objective of refactoring to use error returns instead of panics.

The isNeedOracleSetRequest function still uses a method that can panic, which could be further improved to fully align with the PR's goals.

The changes enhance the robustness of the code by providing better error propagation and the potential for more detailed error logging. This will likely improve debugging and error handling in production environments.

x/crosschain/keeper/pending_execute_claim.go (7)

4-5: Approved: Addition of "fmt" package for error handling

The import of the "fmt" package is necessary for using fmt.Errorf in error handling.


11-11: Updated function signature to return error

Changing the SavePendingExecuteClaim function to return an error enhances error handling by allowing callers to handle potential failures gracefully.


15-15: Replaced panic with error return in SavePendingExecuteClaim

Returning the error instead of panicking improves robustness and allows for proper error propagation.


21-21: Updated function signature to return error

Modifying the GetPendingExecuteClaim function to return an error allows for more informative error handling.


25-25: Return error when claim not found

Returning an error when the claim is not found provides clearer feedback to the caller compared to a boolean value.


29-29: Replaced panic with error return in GetPendingExecuteClaim

Returning the unmarshalling error instead of panicking enhances the method's robustness and allows callers to handle errors appropriately.


31-31: Return claim with nil error upon success

Returning the claim along with a nil error aligns with Go conventions for successful operations.

x/crosschain/keeper/attestation_handler.go (3)

14-14: Properly propagate errors from SavePendingExecuteClaim

The change at line 14 ensures that errors from SavePendingExecuteClaim are correctly returned, enhancing error handling and preventing silent failures.


17-17: Properly propagate errors from OutgoingTxBatchExecuted

The change at line 17 ensures that any errors from OutgoingTxBatchExecuted are properly returned, improving error propagation and maintaining consistent error handling across the codebase.


31-33: Handle errors from GetPendingExecuteClaim appropriately

By checking and returning errors from GetPendingExecuteClaim, the code at lines 31-33 now correctly handles potential errors, ensuring that the function does not proceed with invalid data.

x/crosschain/keeper/outgoing_tx.go (4)

74-74: Good refactoring: Return errors instead of panicking

Changing the function to return errors instead of panicking enhances robustness and allows callers to handle errors gracefully.

Also applies to: 103-103


84-85: Ensure proper error handling within iteration

In the IterateOutgoingTxBatches callback, you're assigning err and breaking the loop by returning true when an error occurs. Ensure that this pattern correctly propagates the first encountered error and that subsequent errors won't be silently ignored.


90-92: Properly propagating errors after batch processing

Good job checking for errors after the iteration and returning them to the caller. This ensures that any issues encountered during batch refunds are not overlooked.


74-74: Verify all callers handle the new error return

Since OutgoingTxBatchExecuted now returns an error, ensure that all callers of this function have been updated to handle the error appropriately.

Run the following script to find all usages of OutgoingTxBatchExecuted and check for proper error handling:

x/crosschain/keeper/attestation.go (5)

49-51: Proper Error Handling in Attest Function

Adding error checking for k.TryAttestation(ctx, att, claim) and returning the error improves the robustness of the Attest function by ensuring that any issues during attestation are correctly propagated to the caller.


64-64: Updated TryAttestation Signature to Return Error

Changing the TryAttestation method to return an error allows for better error propagation and handling throughout the codebase, enhancing overall reliability.


76-76: Return Error When Oracle Not Found

Returning types.ErrNoFoundOracle when an oracle is not found ensures that this scenario is properly reported and can be handled by the calling function, preventing potential nil pointer dereferences or unexpected behavior.


107-112: Added Error Checks for Cleanup Functions

Introducing error handling for k.cleanupTimedOutBatches(ctx) and k.cleanupTimeOutBridgeCall(ctx) ensures that any errors during the cleanup process are not silently ignored but are properly propagated and can be addressed.


117-117: Explicit Return Statement in TryAttestation

Including an explicit return nil at the end of the TryAttestation function clarifies the function's exit points and ensures consistent return behavior.

if err != nil {
panic("couldn't cast to claim")
}
claim := types.MustUnpackAttestationClaim(k.cdc, &att)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consistent change, but reiterate caution on MustUnpackAttestationClaim

This change is consistent with the modification on line 95. However, the same concerns apply here regarding the potential for panics during genesis initialization.

Consider applying the same solution as suggested for line 95 to maintain consistency in error handling throughout the function.

if err != nil {
panic(fmt.Errorf("covert power diff to dec err, powerDiff: %v, err: %w", powerDiff, err))
}
powerDiffDec := sdkmath.LegacyMustNewDecFromStr(powerDiff)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using error handling instead of LegacyMustNewDecFromStr

While using sdkmath.LegacyMustNewDecFromStr simplifies the code, it still has the potential to panic if the input string is not a valid decimal. This doesn't fully align with the PR objective of replacing panics with error returns.

Consider using LegacyNewDecFromStr instead and propagating the error:

powerDiffDec, err := sdkmath.LegacyNewDecFromStr(powerDiff)
if err != nil {
    return currentOracleSet, false
}

This approach would handle potential errors gracefully without panicking, which is more in line with the PR's objectives.

batch := k.GetOutgoingTxBatch(ctx, tokenContract, batchNonce)
if batch == nil {
panic(fmt.Sprintf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce))
return fmt.Errorf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Standardize error generation using types package

Instead of using fmt.Errorf, consider using the error types defined in the types package for consistency. For example:

-return fmt.Errorf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce)
+return types.ErrInvalid.Wrapf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce)

This aligns with existing error handling patterns in the codebase.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return fmt.Errorf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce)
return types.ErrInvalid.Wrapf("unknown batch nonce for outgoing tx batch %s %d", tokenContract, batchNonce)

if err != nil {
panic("couldn't cast to claim")
}
claim := types.MustUnpackAttestationClaim(k.cdc, att)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle Potential Panic from MustUnpackAttestationClaim

Using types.MustUnpackAttestationClaim can lead to a panic if unpacking fails. To improve reliability, consider handling the error explicitly by using types.UnpackAttestationClaim and managing any potential errors.

Apply this change to handle the error gracefully:

-		claim := types.MustUnpackAttestationClaim(k.cdc, att)
+		claim, err := types.UnpackAttestationClaim(k.cdc, att)
+		if err != nil {
+			k.Logger(ctx).Error("Failed to unpack attestation claim", "error", err)
+			continue // Skip this attestation or handle the error appropriately
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
claim := types.MustUnpackAttestationClaim(k.cdc, att)
claim, err := types.UnpackAttestationClaim(k.cdc, att)
if err != nil {
k.Logger(ctx).Error("Failed to unpack attestation claim", "error", err)
continue // Skip this attestation or handle the error appropriately
}

Comment on lines +283 to +288
func MustUnpackAttestationClaim(cdc codectypes.AnyUnpacker, att *Attestation) ExternalClaim {
var msg ExternalClaim
err := cdc.UnpackAny(att.Claim, &msg)
return msg, err
if err := cdc.UnpackAny(att.Claim, &msg); err != nil {
panic(err)
}
return msg
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Reconsider using panic for error handling in MustUnpackAttestationClaim

Changing the function to panic on error can lead to unintended crashes if the panic is not recovered elsewhere in the application. It's generally better practice to return an error and allow the caller to handle it gracefully.

Consider modifying the function to return an error instead of panicking.

Apply this diff to change the function to return an error:

-func MustUnpackAttestationClaim(cdc codectypes.AnyUnpacker, att *Attestation) ExternalClaim {
+func UnpackAttestationClaim(cdc codectypes.AnyUnpacker, att *Attestation) (ExternalClaim, error) {
    var msg ExternalClaim
    if err := cdc.UnpackAny(att.Claim, &msg); err != nil {
-       panic(err)
+       return nil, err
    }
    return msg
+   return msg, nil
}

Committable suggestion was skipped due to low confidence.

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