8000 introduce slashing for oracle service by leonz789 · Pull Request #224 · imua-xyz/imuachain · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

introduce slashing for oracle service #224

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

Merged
merged 18 commits into from
Nov 21, 2024

Conversation

leonz789
Copy link
Contributor
@leonz789 leonz789 commented Oct 22, 2024

Description

This PR introduce slashing mechanism for oracle service by tracking prices provided by validators and the final prices each round.
We define two cases for slashing&jail:

  1. miss
    • this is much like system downtime slashing but calculated by the missing round for which validators not provided provide efficient price. When the count of missing reach the threshold defined in params, slash&jail will happen.
  2. malicious
    • If a validator provides different price for the same roundID under deterministic source, that message will be considered as malicious. When this message deleted slash&jail will happen immediately.
  • testing
  • cli. query

Closes #XXX

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced integration of slashing capabilities within the Oracle module.
    • New methods for managing validator performance and slashing logic, including InitValidatorReportInfo, SetValidatorReportInfo, and enhanced reporting mechanisms.
    • Introduction of new event types and attribute keys related to oracle slashing events.
    • New SlashingParams structure added to manage slashing parameters effectively.
    • New ValidatorMissedRounds and MissedRound messages for tracking missed reporting rounds.
    • New methods added for retrieving final price lists and evaluating validator performance.
    • Added functionality for managing validator performance tracking within the oracle service.
  • Improvements

    • Refined error handling and data retrieval processes for USD value calculations.
    • Expanded functionality for price aggregation and validation within the aggregator context.
    • Enhanced functionality of the Params struct with new slashing parameters and validation.
    • Improved initialization and export of genesis state to include validator report information and missed rounds.
  • Documentation

    • Improved comments and documentation throughout the codebase to clarify functionality and future considerations.
  • Chores

    • Code cleanup and organization, including the removal of commented-out variables and restructuring of existing methods.

8000

Copy link
Contributor
coderabbitai bot commented Oct 22, 2024

Walkthrough

The changes in this pull request primarily enhance the integration and functionality of the OracleKeeper and SlashingKeeper within the ExocoreApp. Modifications include the addition of new fields, methods, and structures related to slashing parameters and validator performance tracking. Key updates involve the introduction of new protocol buffer definitions, adjustments to existing methods for better error handling, and the establishment of new functionalities for managing validator reports and slashing logic.

Changes

File Path Change Summary
app/app.go Updated ExocoreApp to include SlashingKeeper in OracleKeeper initialization.
proto/exocore/oracle/v1/params.proto Added new import statements and a new field SlashingParams to the Params message. Defined a new message type SlashingParams with multiple fields for slashing-related parameters.
proto/exocore/oracle/v1/slashing.proto Introduced new file defining ValidatorReportInfo message with fields for validator performance tracking.
testutil/keeper/oracle.go Added import for slashingkeeper and updated keeper.NewKeeper method to include slashingkeeper.Keeper{} as a parameter.
x/delegation/keeper/abci.go Added documentation comment regarding the IsPending field in UndelegationRecord.
x/delegation/keeper/delegation_state.go Added a comment in SetStakerShareToZero method suggesting future optimization.
x/operator/keeper/slash.go Enhanced documentation in SlashFromUndelegation and SlashAssets functions, indicating potential future changes.
x/operator/keeper/usd_value.go Refined logic in CalculateUSDValueForOperator and GetOrCalculateOperatorUSDValues methods for better error handling and data retrieval.
x/oracle/keeper/aggregator/aggregator.go Added getFinalPriceList method for retrieving sorted price information. Updated comments for clarity.
x/oracle/keeper/aggregator/calculator.go Removed commented field from roundPrices struct and updated comments in fillPrice method regarding confirmation logic.
x/oracle/keeper/aggregator/context.go Added new methods for retrieving final price lists and evaluating performance. Updated SealRound method signature and enhanced error handling in sanityCheck and checkMsg methods.
x/oracle/keeper/aggregator/worker.go Introduced records field in worker struct and methods for managing price reporting records.
x/oracle/keeper/common/expected_keepers.go Updated import statements and modified KeeperDogfood interface to include new methods for validator management.
x/oracle/keeper/keeper.go Added SlashingKeeper field to Keeper struct and updated NewKeeper constructor to accept it as a parameter.
x/oracle/keeper/slashing.go Introduced functionalities for managing validator performance and slashing operations.
x/oracle/module.go Enhanced BeginBlock and EndBlock methods for better tracking of validator performance and slashing conditions.
x/oracle/types/events.go Added new event types and attribute keys related to oracle operations.
x/oracle/types/expected_keepers.go Introduced SlashingKeeper interface with a new method for jailing validators.
x/oracle/types/key_slashing.go Defined key prefixes and functions for managing slashing-related data.
x/oracle/types/types.go Added new struct AggFinalPrice and simplified existing data structures by removing commented fields.
proto/exocore/oracle/v1/genesis.proto Added import for slashing.proto and updated GenesisState message with new fields for tracking validator performance and missed rounds.
x/oracle/genesis.go Enhanced InitGenesis and ExportGenesis functions to manage validator report and missed round data.
x/oracle/types/genesis.go Introduced NewMissedRound function for creating MissedRound instances.
x/oracle/types/genesis_test.go Updated test cases to validate new Slashing parameters in the Params structure.
x/oracle/types/params.go Added SlashingParams to Params struct and updated validation logic to include slashing parameters.

Possibly related PRs

Suggested labels

enhancement, C:CLI

Suggested reviewers

  • MaxMustermann2
  • trestinlsd
  • TimmyExogenous
  • mikebraver

🐇 In the land of code where bunnies hop,
New features sprout, they never stop!
With slashing and oracles, oh what a sight,
Enhancements abound, making things right!
So let’s celebrate with a joyful cheer,
For every change brings us closer, my dear! 🐰✨


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

Actionable comments posted: 29

🧹 Outside diff range and nitpick comments (18)
proto/exocore/oracle/v1/slashing.proto (1)

8-11: Suggestion: Use snake_case for all field names.

The field names and types are generally appropriate, but there's an inconsistency in naming convention:

  • The startHeight field uses camelCase, while the recommended style for Protocol Buffers is snake_case.
  • Other fields correctly use snake_case.

Consider changing startHeight to start_height for consistency and to follow Protocol Buffers best practices:

-  int64 startHeight = 2;
+  int64 start_height = 2;
🧰 Tools
🪛 buf

9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

🪛 GitHub Check: lint

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

x/oracle/types/key_slashing.go (1)

1-6: Remove commented-out code.

The commented-out constant declaration is unnecessary and should be removed to maintain clean code.

Apply this diff to remove the commented-out code:

-// const (
-// 	SlashingPrefix = "Slashing/"
-// )
x/oracle/types/types.go (1)

39-44: Add comments to explain the AggFinalPrice struct and its fields.

While the struct seems well-structured, adding comments would improve code readability and maintainability. Consider adding a comment explaining the purpose of the AggFinalPrice struct and brief descriptions for each field.

Here's a suggested improvement:

+// AggFinalPrice represents an aggregated final price for an oracle.
 type AggFinalPrice struct {
+	// FeederID is the unique identifier for the feeder
 	FeederID uint64
+	// SourceID is the unique identifier for the price source
 	SourceID uint64
+	// DetID is the deterministic identifier for the price
 	DetID    string
+	// Price is the final aggregated price value
 	Price    string
 }
x/oracle/types/expected_keepers.go (2)

4-5: LGTM. Consider removing the redundant import alias.

The import of the time package is correct and necessary for the new SlashingKeeper interface. However, the alias "time" is redundant as it matches the package name.

You can simplify the import statement:

-time "time"
+import "time"

32-34: LGTM. Consider adding documentation for the interface and method.

The SlashingKeeper interface is well-defined and aligns with the PR objectives to introduce slashing for the oracle service. The JailUntil method signature is correct and uses appropriate types.

To improve code clarity, consider adding documentation comments:

// SlashingKeeper defines the expected slashing keeper used for oracle operations
type SlashingKeeper interface {
    // JailUntil jails a validator until a specified time
    JailUntil(ctx sdk.Context, consAddr sdk.ConsAddress, jailEnd time.Time)
}
x/oracle/types/events.go (2)

5-6: LGTM: New event types for oracle liveness and slashing.

The addition of EventTypeOracleLiveness and EventTypeOracleSlash aligns well with the PR objectives. These will be useful for emitting events related to oracle liveness checks and slashing actions.

Consider adding inline comments to briefly explain the purpose of these new event types for better code documentation.


19-25: LGTM: New attribute keys for slashing and validator performance.

The addition of these attribute key constants (AttributeKeyValidatorKey, AttributeKeyMissedRounds, AttributeKeyHeight, AttributeKeyPower, AttributeKeyReason, AttributeKeyJailed, AttributeKeyBurnedCoins) provides a comprehensive set of keys for events related to oracle liveness and slashing.

Consider grouping these new constants together with a comment to indicate their relation to slashing and validator performance. This would improve code organization and readability.

x/oracle/keeper/keeper.go (1)

28-28: Approve the addition of SlashingKeeper with a minor suggestion.

The addition of SlashingKeeper to the Keeper struct is appropriate for integrating slashing capabilities into the oracle service. This aligns well with the PR objectives.

Consider adding a comment to explain the purpose of this field, e.g.:

// SlashingKeeper provides access to slashing functionality for oracle validators
SlashingKeeper types.SlashingKeeper
testutil/keeper/oracle.go (1)

Line range hint 1-70: Summary: Slashing integration looks good, but verify actual implementation.

The changes to integrate the slashing keeper with the oracle keeper are minimal and align with the PR objectives. However, there are a few points to consider:

  1. Ensure that the slashing keeper is properly initialized and used in the actual oracle keeper implementation, not just in this test utility.
  2. Verify that all necessary changes have been made in other parts of the system to support this integration (e.g., in the main application setup).
  3. Consider adding tests that specifically cover the new slashing functionality in the oracle module.

Given the integration of slashing with the oracle service, it would be beneficial to:

  1. Document the slashing conditions and mechanisms specific to the oracle service.
  2. Ensure that the oracle module's documentation is updated to reflect this new capability.
  3. Consider adding integration tests that cover the interaction between the oracle and slashing modules.
x/operator/keeper/slash.go (2)

26-26: LGTM. Consider adding more context to the comment.

The updated comment clarifies the function's behavior, which is great. To further improve it, consider adding a brief explanation of why this reduction is necessary and its implications in the broader context of the slashing mechanism.


139-139: Good catch. Consider creating an issue to track this enhancement.

The TODO comment identifies an important edge case in the slashing mechanism. To ensure this doesn't get overlooked:

  1. Create a GitHub issue to track this enhancement.
  2. In the issue, detail the steps needed to implement this check and the potential impact on the system.
  3. Consider adding a link to the created issue in this TODO comment for easier tracking.

This will help in maintaining system integrity by properly handling operators with no remaining assets after slashing.

Would you like me to draft the GitHub issue for this enhancement?

x/oracle/keeper/aggregator/worker.go (1)

23-23: Address the TODO comment by moving records into context

The TODO comment indicates that the records field should be moved into the context via .ctx. Refactoring to move records into the context can enhance modularity and maintainability.

Would you like assistance in refactoring the code to move records into the context?

x/oracle/keeper/aggregator/aggregator.go (1)

196-198: Correct typos and ensure consistency in function comments.

  • At line 196, the word "suites" should be "suits" in the TODO comment.
  • The function comment at line 197 mentions GetFinaPriceListForFeederIDs, which does not match the actual function name getFinalPriceList. Additionally, there's a typo in "GetFina"—it should be "GetFinal".

Please correct these typos and update the function comment to accurately reflect the function's name and purpose.

x/oracle/keeper/aggregator/context.go (1)

163-167: Consider removing commented-out code for clarity.

The code block at lines 163-167 is commented out. If this code is no longer needed, it's better to remove it to improve code readability and maintainability.

x/oracle/module.go (4)

164-164: File is not formatted according to gofumpt

The static analysis tool indicates that the file is not gofumpt-ed. Please format the code using gofumpt to ensure consistency and adherence to Go formatting standards.

🧰 Tools
🪛 GitHub Check: Run golangci-lint

[failure] 164-164:
File is not gofumpt-ed (gofumpt)


212-212: Correct typos in comment

The comment contains typos: "feedeerID" should be "feederID", and "srouceID" should be "sourceID".


216-216: Remove outdated TODO comment

The TODO comment states that malicious prices should cause immediate slashing and jailing, which is implemented in the code below. Remove the comment to prevent confusion.


339-339: Fix typo in log message

The log message contains a typo: "missed repoerting price" should be "missed reporting price".

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f7233c7 and bbd64fd.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/slashing.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (20)
  • app/app.go (1 hunks)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
  • proto/exocore/oracle/v1/slashing.proto (1 hunks)
  • testutil/keeper/oracle.go (2 hunks)
  • x/delegation/keeper/abci.go (1 hunks)
  • x/delegation/keeper/delegation_state.go (1 hunks)
  • x/operator/keeper/slash.go (2 hunks)
  • x/operator/keeper/usd_value.go (0 hunks)
  • x/oracle/keeper/aggregator/aggregator.go (4 hunks)
  • x/oracle/keeper/aggregator/calculator.go (0 hunks)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/keeper/aggregator/worker.go (3 hunks)
  • x/oracle/keeper/common/expected_keepers.go (2 hunks)
  • x/oracle/keeper/keeper.go (3 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
  • x/oracle/types/events.go (2 hunks)
  • x/oracle/types/expected_keepers.go (2 hunks)
  • x/oracle/types/key_slashing.go (1 hunks)
  • x/oracle/types/types.go (1 hunks)
💤 Files with no reviewable changes (2)
  • x/operator/keeper/usd_value.go
  • x/oracle/keeper/aggregator/calculator.go
✅ Files skipped from review due to trivial changes (1)
  • x/delegation/keeper/delegation_state.go
🧰 Additional context used
🪛 GitHub Check: lint
proto/exocore/oracle/v1/params.proto

[failure] 8-8:
Import "google/protobuf/timestamp.proto" is unused.


[failure] 9-9:
Import "cosmos_proto/cosmos.proto" is unused.

proto/exocore/oracle/v1/slashing.proto

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

🪛 buf
proto/exocore/oracle/v1/slashing.proto

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

🪛 GitHub Check: Run golangci-lint
x/oracle/keeper/aggregator/context.go

[failure] 214-214:
File is not gofumpt-ed (gofumpt)

x/oracle/keeper/aggregator/worker.go

[failure] 41-41:
func recordMsg.has is unused (unused)


[failure] 47-47:
S1005: unnecessary assignment to the blank identifier (gosimple)

x/oracle/keeper/common/expected_keepers.go

[failure] 4-4:
ST1019: package "cosmossdk.io/math" is being imported more than once (stylecheck)


[failure] 5-5:
ST1019(related information): other import of "cosmossdk.io/math" (stylecheck)

x/oracle/module.go

[failure] 164-164:
File is not gofumpt-ed (gofumpt)

🔇 Additional comments (29)
proto/exocore/oracle/v1/slashing.proto (3)

1-5: LGTM: File structure and package declaration are correct.

The syntax, package declaration, and go_package option are all properly set. The file structure follows common conventions for Protocol Buffers files in Go projects.

🧰 Tools
🪛 buf

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


7-7: LGTM: Message definition is appropriate.

The ValidatorReportInfo message is well-named and follows the correct naming convention. It aligns with the PR objective of introducing slashing capabilities for the oracle service.


1-12: Summary: The new Protocol Buffers file is well-structured and aligns with PR objectives.

The slashing.proto file introduces a new ValidatorReportInfo message type, which is crucial for implementing the slashing mechanism in the oracle service. The file structure, syntax, and package declarations are correct. A minor naming convention issue was identified and a suggestion for improvement was provided.

Overall, this new file contributes positively to the PR's goal of introducing slashing capabilities to the oracle service.

🧰 Tools
🪛 buf

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

🪛 GitHub Check: lint

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

x/oracle/types/key_slashing.go (2)

7-11: LGTM: Well-structured prefix declarations.

The prefix declarations are clear, efficient, and follow good naming conventions. The use of append for creating composite prefixes is appropriate.


1-24: Overall assessment: Well-implemented slashing key generation.

This new file introduces a solid foundation for managing slashing-related data in the oracle service. The key generation functions are well-designed and efficient. However, there are a few minor points to address:

  1. Remove the commented-out constant declaration at the beginning of the file.
  2. Ensure that DelimiterForCombinedKey and Uint64Bytes are properly defined and imported.

Once these minor issues are addressed, the implementation will be robust and ready for integration into the larger system.

To ensure the completeness of the slashing implementation, let's verify the integration of this new functionality with the oracle keeper:

#!/bin/bash
# Description: Verify the integration of slashing functionality with the oracle keeper

# Test 1: Search for SlashingKeeper in the OracleKeeper struct
echo "Searching for SlashingKeeper in the OracleKeeper struct:"
rg -A 5 "type OracleKeeper struct" | rg "SlashingKeeper"

# Test 2: Search for usage of slashing functions in the oracle module
echo "Searching for usage of slashing functions in the oracle module:"
rg -A 5 "SlashingValidatorReportInfoKey|SlashingMissedBitArrayPrefix|SlashingMissedBitArrayKey" x/oracle

Please ensure that the slashing functionality is properly integrated with the oracle keeper and used appropriately in the oracle module.

x/oracle/types/types.go (2)

Line range hint 1-58: Overall assessment of changes in types.go

The additions to this file, namely the AggFinalPrice struct and DelimiterForCombinedKey variable, appear to enhance the oracle system's functionality, particularly in aggregating final prices. These changes are consistent with the existing code style and practices.

Key points:

  1. The AggFinalPrice struct provides a clear structure for representing aggregated final prices.
  2. The DelimiterForCombinedKey variable introduces a standard delimiter for combined keys.

To further improve the code:

  1. Add comments to explain the purpose and usage of new elements.
  2. Verify that the chosen delimiter doesn't conflict with file paths or URLs in the broader context of the application.

These changes align well with the PR objective of introducing slashing for the oracle service, as they provide necessary data structures for price aggregation, which could be used in the slashing mechanism.


51-51: Add a comment for DelimiterForCombinedKey and consider potential conflicts.

The purpose and usage of this delimiter should be clarified with a comment. Additionally, consider if using '/' might cause any conflicts, especially if the combined keys are used in file paths or URLs.

Here's a suggested improvement:

+// DelimiterForCombinedKey is used to separate parts in combined keys.
+// Note: Ensure this doesn't conflict with file path or URL usage.
 var DelimiterForCombinedKey = byte('/')

To verify potential conflicts, let's search for uses of this delimiter:

✅ Verification successful

Add a descriptive comment for DelimiterForCombinedKey. No potential conflicts with file paths or URLs detected.

  • Add a comment in x/oracle/types/types.go at line 51 to clarify the purpose and usage of DelimiterForCombinedKey.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for uses of DelimiterForCombinedKey and potential conflicts with file paths or URLs

# Test 1: Find direct uses of DelimiterForCombinedKey
echo "Direct uses of DelimiterForCombinedKey:"
rg "DelimiterForCombinedKey" -A 3

# Test 2: Look for potential conflicts with file paths
echo "\nPotential conflicts with file paths:"
rg "filepath\.Join|os\.Open|ioutil\.ReadFile" -A 3

# Test 3: Look for potential conflicts with URLs
echo "\nPotential conflicts with URLs:"
rg "url\.Parse|http\.Get" -A 3

Length of output: 7339

x/oracle/types/expected_keepers.go (1)

Line range hint 1-34: Overall, the changes look good and align with the PR objectives.

The introduction of the SlashingKeeper interface in this file is a crucial part of implementing the slashing mechanism for the oracle service. These changes, combined with the modifications mentioned in the AI-generated summary (such as updates to the OracleKeeper and Keeper structs in other files), create a solid foundation for integrating slashing capabilities into the oracle system.

To ensure the completeness of this implementation:

  1. Verify that the SlashingKeeper is properly initialized and passed to the OracleKeeper:

  2. Confirm that the JailUntil method is called in appropriate places within the oracle module:

These verifications will help ensure that the slashing mechanism is properly integrated throughout the oracle module.

x/oracle/types/events.go (3)

4-4: LGTM: Improved code formatting.

The reformatting of EventTypeCreatePrice enhances code consistency.


32-32: LGTM: New attribute value for missing price reports.

The addition of AttributeValueMissingReportPrice provides a clear identifier for events related to missing price reports in the oracle service.


Line range hint 1-33: Overall assessment: Good additions with one minor issue.

The new constants for event types and attribute keys/values align well with the PR objectives of introducing slashing for the oracle service. They provide a comprehensive set of identifiers for events related to oracle liveness and slashing actions.

However, please address the issue with the AttributeValueMaliciousReportPrice constant value before merging this PR.

Additionally, consider adding brief inline comments for the new constants to improve code documentation, and grouping related constants for better organization.

x/oracle/keeper/keeper.go (3)

43-43: LGTM: SlashingKeeper parameter added correctly.

The addition of the slashingKeeper parameter to the NewKeeper function is consistent with the new field in the Keeper struct and follows good dependency injection practices.


63-63: LGTM: SlashingKeeper assigned correctly.

The assignment of the slashingKeeper parameter to the SlashingKeeper field in the Keeper struct initialization is correct and completes the integration of slashing capabilities.


Line range hint 28-63: Summary: Slashing integration looks good, verify dependencies.

The changes to integrate slashing capabilities into the oracle keeper are well-implemented and consistent. The new SlashingKeeper field, parameter, and assignment are correctly added.

To ensure all dependencies are correctly set up, please run the following command:

testutil/keeper/oracle.go (1)

24-24: LGTM: Slashing keeper import added correctly.

The new import for the slashing keeper is appropriately placed and follows the existing import structure. This addition aligns with the PR objective of introducing slashing for the oracle service.

x/oracle/keeper/common/expected_keepers.go (3)

57-57: LGTM: Consistent type name update.

The change from stakingTypes.ValidatorI to stakingtypes.ValidatorI is consistent with the import rename and improves code consistency.


59-59: LGTM: Consistent type name update.

The change from stakingTypes.Validator to stakingtypes.Validator is consistent with the import rename and improves code consistency.


62-64: New methods align with PR objectives, but clarification needed.

The new methods ValidatorByConsAddr, SlashWithInfractionReason, and Jail are well-aligned with the PR objectives of introducing slashing mechanisms. They enhance the interface's capabilities for validator management and penalization.

Could you please clarify the difference between the new ValidatorByConsAddr method and the existing GetValidatorByConsAddr method? They seem to serve similar purposes but return different types (stakingtypes.ValidatorI vs stakingtypes.Validator, bool).

To help verify the usage and necessity of both methods, please run the following script:

This will help us understand if both methods are necessary and how they are used in the codebase.

✅ Verification successful

Validator methods usage confirmed and appropriate.

The ValidatorByConsAddr and GetValidatorByConsAddr methods serve distinct purposes, with the former providing an interface type for flexibility and the latter offering concrete retrieval with existence checking. Their usage across the codebase justifies their coexistence and aligns with the PR objectives.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usages of both ValidatorByConsAddr and GetValidatorByConsAddr methods

echo "Usages of ValidatorByConsAddr:"
rg "ValidatorByConsAddr\(" -A 3

echo "\nUsages of GetValidatorByConsAddr:"
rg "GetValidatorByConsAddr\(" -A 3

Length of output: 6235

x/operator/keeper/slash.go (1)

Line range hint 1-269: Overall, the changes improve documentation without altering core logic.

The modifications in this file are focused on enhancing documentation and planning for future improvements:

  1. The updated comment for SlashFromUndelegation provides better clarity on the function's behavior.
  2. The new TODO comment in SlashAssets identifies an important edge case for future optimization.

These changes demonstrate attention to detail and forward-thinking about the slashing mechanism. They don't introduce immediate risks or alterations to the existing logic but pave the way for future enhancements.

To maintain this momentum:

  1. Consider reviewing other functions in this file for similar documentation improvements.
  2. Ensure that the TODO item is properly tracked and addressed in future development cycles.

Great job on continuously improving the codebase!

proto/exocore/oracle/v1/params.proto (2)

39-40: Integration of slashing parameters into Params message.

Adding SlashingParams slashing = 12; appropriately extends the Params message to include slashing-related configurations.


53-86: Definition of SlashingParams message is well-structured.

The SlashingParams message is correctly defined with appropriate field types and options to support the slashing functionality.

x/oracle/keeper/aggregator/context.go (6)

7-7: Importing 'sort' package is appropriate.

The addition of "sort" to the imports is necessary for the sorting operations introduced in the code.


168-173: Logic for handling sealed feederWorker is correctly implemented.

The updated code properly records messages for performance evaluation when the feederWorker is sealed before returning the appropriate error.


213-220: Feeder IDs are correctly sorted before processing.

Sorting feederIDs ensures that the IDs are accessed in a consistent order, which is important for slashing calculations.

🧰 Tools
🪛 GitHub Check: Run golangci-lint

[failure] 214-214:
File is not gofumpt-ed (gofumpt)


231-236: Properly record when rounds reach the end of their window.

Appending feederID to windowClosed when a round reaches the MaxNonce offset aids in tracking and handling slashing operations effectively.


259-259: Return statement in SealRound updated appropriately.

Including windowClosed in the return statement aligns with the updated function signature and ensures all relevant data is returned.


369-380: New method GetFinalPriceListForFeederIDs is implemented correctly.

The function efficiently retrieves final price lists for the specified feeder IDs, ensuring the results are ordered as required.

x/oracle/module.go (2)

27-27: Import statement for staking types

The import of stakingtypes is necessary for slashing functionality and is appropriately added.


183-188: Proper initialization of report info for validator updates

The code correctly initializes ValidatorReportInfo for validators with positive power, ensuring proper tracking for slashing purposes.

Copy link
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.

Actionable comments posted: 24

🧹 Outside diff range and nitpick comments (23)
proto/exocore/oracle/v1/slashing.proto (1)

7-12: LGTM: Well-structured ValidatorReportInfo message.

The ValidatorReportInfo message is well-defined with appropriate field types and unique tag numbers.

Consider adding comments to describe the purpose of each field, especially for fields like index_offset and missed_rounds_counter, to improve code readability and maintainability.

🧰 Tools
🪛 GitHub Check: lint

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

🪛 buf

9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

x/oracle/types/key_slashing.go (2)

1-6: Remove commented-out code.

The commented-out constant definition for SlashingPrefix is no longer needed as it has been replaced by a variable declaration. Remove this commented-out code to improve code cleanliness.

-// const (
-// 	SlashingPrefix = "Slashing/"
-// )

17-20: Clarify the purpose of DelimiterForCombinedKey.

The function is well-implemented, but the use of DelimiterForCombinedKey is not explained. Consider adding a comment to clarify its purpose in the key construction.

x/oracle/types/types.go (3)

39-44: Consider adding comments and reviewing the Price field type.

The new AggFinalPrice struct looks good overall, but consider the following suggestions:

  1. Add comments for each field to explain their purpose and any constraints. This will improve code maintainability and make it easier for other developers to understand and use the struct correctly.

  2. The Price field is currently a string. While this allows for high precision, it may require parsing for numerical operations. Consider using a numeric type (e.g., sdkmath.Int or decimal.Decimal) if precise calculations are needed, or add a comment explaining why a string is preferred.

Example with comments:

type AggFinalPrice struct {
    FeederID uint64 // Unique identifier for the price feeder
    SourceID uint64 // Identifier for the price source
    DetID    string // Deterministic ID for the price (explain its purpose)
    Price    string // Price value as a string (explain precision/format)
}

51-51: Add a comment explaining the usage of DelimiterForCombinedKey.

The addition of DelimiterForCombinedKey is a good practice for maintaining consistency in key generation. However, its purpose and usage are not immediately clear from the context.

Consider adding a comment to explain where and how this delimiter is used. For example:

// DelimiterForCombinedKey is used to separate components when creating composite keys
// in the oracle module's key-value store.
var DelimiterForCombinedKey = byte('/')

This will help other developers understand the purpose of this variable and use it correctly.


Line range hint 1-38: Remove commented-out code and update documentation.

There are several commented-out fields in the OracleInfo struct, specifically within the Token and Feeder sub-structs. While these comments might be temporary during development, it's generally better to remove unused code rather than commenting it out. This helps maintain a clean and clear codebase.

Consider the following actions:

  1. If these fields are no longer needed, remove them entirely instead of keeping them commented out.
  2. If there's a reason to keep track of these removed fields, consider adding a comment explaining why they were removed and when they might be needed again.
  3. Update any related documentation or comments to reflect the current structure of the OracleInfo struct.

Example:

type OracleInfo struct {
    // ... (other fields)
    Token struct {
        Name     string `json:"name"`
        Desc     string
        Decimal  string `json:"decimal"`
        Contract string `json:"contract"`
        AssetID  string `json:"asset_id"`
        // Removed: Chain struct - no longer needed as of <date/PR>
    } `json:"token"`
    Feeder struct {
        Interval string `json:"interval"`
        // Removed: Start, End, RuleID fields - replaced by <new mechanism> as of <date/PR>
    } `json:"feeder"`
    // ... (other fields)
}
x/oracle/types/expected_keepers.go (3)

4-4: Remove the alias for the time package import.

The time package is a standard Go package and doesn't require an alias. Using an alias for standard packages is not a common practice and may lead to confusion.

Consider changing the import statement to:

-time "time"
+import "time"

32-34: LGTM! Consider adding documentation for the SlashingKeeper interface.

The SlashingKeeper interface is well-defined and consistent with the codebase conventions. The JailUntil method signature is clear and uses appropriate types.

To improve code maintainability, consider adding a brief comment explaining the purpose of the SlashingKeeper interface and the JailUntil method. For example:

// SlashingKeeper defines the expected slashing keeper used for oracle operations
type SlashingKeeper interface {
    // JailUntil jails a validator until a specified time
    JailUntil(sdk.Context, sdk.ConsAddress, time.Time)
}

Action Required: Integrate SlashingKeeper into OracleKeeper

The SlashingKeeper interface is defined but not integrated into the OracleKeeper struct or initialized in the NewKeeper function. Please ensure that SlashingKeeper is properly incorporated to enable its intended functionality within the Oracle module.

  • Update OracleKeeper to include SlashingKeeper.
  • Initialize SlashingKeeper in the NewKeeper function.
🔗 Analysis chain

Line range hint 1-34: Summary: SlashingKeeper integration enhances oracle service capabilities.

The introduction of the SlashingKeeper interface aligns well with the PR objectives of implementing slashing mechanisms for the oracle service. This addition allows for better integration between the oracle and slashing modules, enabling more sophisticated validator management.

Key points:

  1. The new SlashingKeeper interface provides a method for jailing validators until a specified time.
  2. The changes are minimal and non-disruptive to existing code.
  3. The integration enhances the system's ability to penalize misbehaving validators in the oracle service.

To ensure proper integration, please run the following script to check for consistent usage of the new SlashingKeeper interface across the codebase:


[/run_scripts]

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of SlashingKeeper in relevant files

# Test 1: Check for SlashingKeeper in OracleKeeper
echo "Checking OracleKeeper for SlashingKeeper:"
rg -p "type OracleKeeper struct" -A 10 | rg "SlashingKeeper"

# Test 2: Check for SlashingKeeper initialization in NewKeeper
echo "Checking NewKeeper for SlashingKeeper initialization:"
rg "func NewKeeper\(" -A 15 | rg "SlashingKeeper:"

# Test 3: Check for JailUntil method calls
echo "Checking for JailUntil method calls:"
rg "JailUntil\("

Length of output: 650


Script:

#!/bin/bash
# Description: Search for any implementations or references of SlashingKeeper

# Test 4: Search for implementations of SlashingKeeper interface
echo "Searching for implementations of SlashingKeeper:"
rg "type .*SlashingKeeper" --type go

# Test 5: Search for references to SlashingKeeper in function parameters
echo "Searching for function parameters using SlashingKeeper:"
rg "SlashingKeeper" --type go | rg "\("

Length of output: 721

x/oracle/types/events.go (2)

19-25: LGTM: New attribute keys for slashing-related data.

The new attribute key constants (AttributeKeyValidatorKey, AttributeKeyMissedRounds, AttributeKeyHeight, AttributeKeyPower, AttributeKeyReason, AttributeKeyJailed, AttributeKeyBurnedCoins) are well-defined and consistent with the existing naming convention. They provide necessary keys for slashing-related information.

Consider renaming AttributeKeyValidatorKey to AttributeKeyValidator for consistency with other attribute keys that don't include the word "Key" in their names.


Issue Found: Duplicate Attribute Value Assignment

The constant AttributeValueMaliciousReportPrice is incorrectly assigned the value "missing_report_price". It should likely be "malicious_report_price".

  • File: x/oracle/types/events.go
    • Line: AttributeValueMaliciousReportPrice = "missing_report_price"
🔗 Analysis chain

Line range hint 1-33: Summary: Comprehensive addition of constants for oracle slashing mechanism.

The changes in this file provide a solid foundation for implementing the oracle slashing mechanism. The new constants cover event types, attribute keys, and attribute values necessary for tracking oracle liveness and applying slashes. These additions will enable detailed event logging and data management for the slashing feature.

To ensure these constants are being utilized correctly, please run the following script to check their usage across the codebase:

This will help ensure that the new constants are being properly integrated into the slashing logic throughout the project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of new constants in the codebase.

echo "Checking usage of new event types:"
rg "EventTypeOracleLiveness|EventTypeOracleSlash" --type go

echo "\nChecking usage of new attribute keys:"
rg "AttributeKeyValidatorKey|AttributeKeyMissedRounds|AttributeKeyHeight|AttributeKeyPower|AttributeKeyReason|AttributeKeyJailed|AttributeKeyBurnedCoins" --type go

echo "\nChecking usage of new attribute values:"
rg "AttributeValueMissingReportPrice|AttributeValueMaliciousReportPrice" --type go

Length of output: 3116

x/oracle/keeper/keeper.go (1)

28-28: LGTM. Consider adding a comment for the new field.

The addition of SlashingKeeper aligns well with the PR objective of introducing slashing for the oracle service. This change enables the Keeper to interact with slashing functionality.

Consider adding a brief comment explaining the purpose of this field:

// SlashingKeeper handles slashing operations for oracle validators
SlashingKeeper types.SlashingKeeper
testutil/keeper/oracle.go (2)

56-56: Consider initializing SlashingKeeper with necessary dependencies.

The addition of slashingkeeper.Keeper{} as an argument to NewKeeper is correct and aligns with the PR objectives. However, for more robust testing, consider initializing the SlashingKeeper with its necessary dependencies instead of passing an empty struct.

You might want to create a mock or properly initialized SlashingKeeper for testing purposes. For example:

slashingKeeper := slashingkeeper.NewKeeper(
    cdc,
    storeKey,
    &stakingKeeper,
    authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

Replace storeKey and stakingKeeper with appropriate values for your test environment.


Line range hint 1-70: Summary: Integration of SlashingKeeper into OracleKeeper test utility

The changes in this file successfully integrate the SlashingKeeper into the OracleKeeper test utility. This update aligns with the PR's objective of introducing slashing mechanisms for the oracle service. The modifications are minimal yet impactful, setting the groundwork for testing the new slashing functionality within the oracle module.

To further enhance the test utility:

  1. Consider initializing the SlashingKeeper with proper dependencies for more comprehensive testing.
  2. Update any existing tests that use this utility to ensure they account for the new slashing functionality.
  3. Add new tests specifically targeting the interaction between the OracleKeeper and SlashingKeeper.

These enhancements will help ensure the robustness and reliability of the new slashing mechanisms in the oracle service.

x/oracle/keeper/aggregator/aggregator.go (1)

128-128: LGTM: Efficiency improvement.

The addition of the break statement is a good optimization. It prevents unnecessary iterations once a matching price is found.

Consider moving the entire price-finding logic into a separate helper function for improved readability and maintainability.

x/operator/keeper/slash.go (2)

139-139: Consider creating an issue for the proposed enhancement.

The TODO comment suggests an important consideration for handling edge cases when all assets fall to zero. To ensure this doesn't get overlooked:

  1. Create a GitHub issue to track this enhancement.
  2. In the issue, detail the proposed checks and actions:
    • Check if pendingUndelegation is also zero
    • Delete the item if both are zero
    • Opt out the operator if all assets fall to zero

This will help in prioritizing and implementing this improvement in the future.

Would you like me to create a draft for this GitHub issue?


Add Comprehensive Tests for Slashing Edge Cases

The current test suite does not cover critical slashing scenarios such as varying slashing proportions, slashing when assets are near zero, multiple consecutive slashes, and interactions between slashing and undelegation. It's essential to implement tests for these cases to ensure the reliability and robustness of the slashing mechanism.

  • Implement tests for slashing with various proportions.
  • Create scenarios where assets are close to zero and validate slashing behavior.
  • Test multiple consecutive slashes to ensure system stability.
  • Verify the interaction between slashing and undelegation processes.
🔗 Analysis chain

Line range hint 1-285: Overall assessment of slashing mechanism.

The changes in this file are minor and improve documentation without altering core functionality. However, given the critical nature of slashing operations, it's crucial to ensure comprehensive testing of the entire slashing mechanism, including edge cases such as:

  1. Slashing with various proportions
  2. Slashing when assets are close to zero
  3. Multiple consecutive slashes
  4. Interaction between slashing and undelegation processes

Consider adding or updating integration tests to cover these scenarios thoroughly.

To assist in verifying the slashing mechanism, you can run the following script to identify existing tests related to slashing:

This script will help identify existing test coverage and areas where additional tests might be needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find existing test files related to slashing

echo "Searching for test files related to slashing..."
fd -e go -e sh test | rg -i 'slash|undelegat|jail'

echo "Searching for test functions related to slashing within Go files..."
rg -t go '(?i)func.*test.*(?:slash|undelegat|jail)' -g '*_test.go'

Length of output: 1992


Script:

#!/bin/bash
# Description: Check if tests cover slashing with various proportions

echo "Searching for tests covering slashing with various proportions..."
rg -i 'test.*slash.*proportion' $(fd -e go -e sh test)

echo "Searching for tests covering slashing when assets are close to zero..."
rg -i 'test.*slash.*zero|close to zero|minimum' $(fd -e go -e sh test)

echo "Searching for tests covering multiple consecutive slashes..."
rg -i 'test.*slash.*multiple|consecutive|repeated' $(fd -e go -e sh test)

echo "Searching for tests covering interaction between slashing and undelegation..."
rg -i 'test.*slash.*undelegation.*interaction|integration|combined' $(fd -e go -e sh test)

Length of output: 23366

proto/exocore/oracle/v1/params.proto (1)

39-39: Correct the grammatical error in the comment for clarity.

Update the comment to improve readability and grammar. It should read: Slashing defines the slashing related params.

Apply this diff to correct the comment:

-// slashing defined the slashing related params
+// Slashing defines the slashing related params
x/oracle/keeper/aggregator/worker.go (1)

47-49: Simplify assignment in get method

The assignment to the blank identifier _ is unnecessary. You can simplify the code by directly retrieving the value.

Apply this diff to streamline the code:

-func (r recordMsg) get(validator string, feederID, sourceID uint64) []*types.PriceTimeDetID {
-	v, _ := r[recordKey{validator, feederID, sourceID}]
+func (r recordMsg) get(validator string, feederID, sourceID uint64) []*types.PriceTimeDetID {
+	v := r[recordKey{validator, feederID, sourceID}]
	return v
}
🧰 Tools
🪛 GitHub Check: Run golangci-lint

[failure] 47-47:
S1005: unnecessary assignment to the blank identifier (gosimple)

x/oracle/keeper/aggregator/context.go (3)

384-390: Log a warning when feederWorker is nil in PerformanceReview

In the PerformanceReview function, if feederWorker is nil, the code treats the validator as effective and honest by default. Since this scenario "should not happen," it would be helpful to log a warning or error message to aid in debugging and to make potential issues more visible.

Apply this diff to add a log message:

 if feederWorker == nil {
+	ctx.Logger().Warn("feederWorker is nil in PerformanceReview", "feederID", finalPrice.FeederID)
 	// something wrong happened in the agc, so we just skip this round by treat the validator as effective&honest
 	exist = true
 	matched = true

218-220: Handle potential large feederIDs slices efficiently

When sorting large slices of feederIDs, consider the efficiency of the sorting algorithm. The current use of sort.Slice is appropriate, but if feederIDs can become very large, investigate using more efficient sorting methods or data structures to optimize performance.


Ensure all SealRound calls handle windowClosed return value

The following usages of SealRound do not handle the new windowClosed return value:

  • x/oracle/keeper/single.go
  • x/oracle/keeper/aggregator/context_test.go

Please update these call sites to handle windowClosed to maintain consistency and prevent potential issues.

🔗 Analysis chain

Line range hint 212-259: Ensure all calls to SealRound handle the new return value windowClosed

The SealRound method's signature has been updated to include an additional return value windowClosed []uint64. Verify that all calls to this method throughout the codebase are updated to handle this new return value to prevent potential issues.

Run the following script to find all usages of SealRound:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to SealRound to ensure they're updated.

# Search for SealRound method calls
rg 'SealRound\('

Length of output: 573

🧰 Tools
🪛 GitHub Check: Run golangci-lint

[failure] 214-214:
File is not gofumpt-ed (gofumpt)

x/oracle/module.go (1)

340-340: Fix typographical error in log message

There's a typo in the log message: "repoerting" should be "reporting".

Suggested change:

     "validator would have been slashed for too many missed repoerting price, but was either not found in store or already jailed",
+    "validator would have been slashed for too many missed reporting price, but was either not found in store or already jailed",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f7233c7 and bbd64fd.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/slashing.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (20)
  • app/app.go (1 hunks)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
  • proto/exocore/oracle/v1/slashing.proto (1 hunks)
  • testutil/keeper/oracle.go (2 hunks)
  • x/delegation/keeper/abci.go (1 hunks)
  • x/delegation/keeper/delegation_state.go (1 hunks)
  • x/operator/keeper/slash.go (2 hunks)
  • x/operator/keeper/usd_value.go (0 hunks)
  • x/oracle/keeper/aggregator/aggregator.go (4 hunks)
  • x/oracle/keeper/aggregator/calculator.go (0 hunks)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/keeper/aggregator/worker.go (3 hunks)
  • x/oracle/keeper/common/expected_keepers.go (2 hunks)
  • x/oracle/keeper/keeper.go (3 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
  • x/oracle/types/events.go (2 hunks)
  • x/oracle/types/expected_keepers.go (2 hunks)
  • x/oracle/types/key_slashing.go (1 hunks)
  • x/oracle/types/types.go (1 hunks)
💤 Files with no reviewable changes (2)
  • x/operator/keeper/usd_value.go
  • x/oracle/keeper/aggregator/calculator.go
✅ Files skipped from review due to trivial changes (2)
  • x/delegation/keeper/abci.go
  • x/delegation/keeper/delegation_state.go
🧰 Additional context used
🪛 GitHub Check: lint
proto/exocore/oracle/v1/params.proto

[failure] 8-8:
Import "google/protobuf/timestamp.proto" is unused.


[failure] 9-9:
Import "cosmos_proto/cosmos.proto" is unused.

proto/exocore/oracle/v1/slashing.proto

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

🪛 buf
proto/exocore/oracle/v1/slashing.proto

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

🪛 GitHub Check: Run golangci-lint
x/oracle/keeper/aggregator/context.go

[failure] 214-214:
File is not gofumpt-ed (gofumpt)

x/oracle/keeper/aggregator/worker.go

[failure] 41-41:
func recordMsg.has is unused (unused)


[failure] 47-47:
S1005: unnecessary assignment to the blank identifier (gosimple)

x/oracle/keeper/common/expected_keepers.go

[failure] 4-4:
ST1019: package "cosmossdk.io/math" is being imported more than once (stylecheck)


[failure] 5-5:
ST1019(related information): other import of "cosmossdk.io/math" (stylecheck)

x/oracle/module.go

[failure] 164-164:
File is not gofumpt-ed (gofumpt)

🪛 GitHub Check: CodeQL
x/oracle/module.go

[warning] 164-166: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 205-347: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 229-229: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 302-302: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

🔇 Additional comments (25)
proto/exocore/oracle/v1/slashing.proto (3)

1-3: LGTM: Proper syntax and package declaration.

The file correctly uses proto3 syntax and declares an appropriate package name that aligns with the file path.

🧰 Tools
🪛 buf

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


5-5: LGTM: Correct Go package option.

The go_package option is properly set to point to the correct GitHub repository and package within the project, following best practices for Go module organization.


1-12: Verify directory structure convention for proto files.

The static analysis tool flagged that files with package "exocore.oracle.v1" should be within a directory "exocore/oracle/v1" relative to root, but this file is in "proto/exocore/oracle/v1".

Please confirm if the current directory structure ("proto/exocore/oracle/v1") is intentional and aligns with the project's conventions. If not, consider moving the file to match the package name exactly.

To verify the current structure, run:

✅ Verification successful

Directory structure for proto files adheres to project conventions.

All .proto files are correctly located within the proto/ directory.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the directory structure for proto files

# Test: List all .proto files in the project
fd -e proto

# Test: Check if there's a consistent 'proto' directory for all .proto files
fd -e proto | grep -v '^proto/' && echo "Some .proto files are not in the 'proto' directory"

Length of output: 4201

🧰 Tools
🪛 GitHub Check: lint

[failure] 9-9:
Field name "startHeight" should be lower_snake_case, such as "start_height".

🪛 buf

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)


9-9: Field name "startHeight" should be lower_snake_case, such as "start_height".

(FIELD_LOWER_SNAKE_CASE)

x/oracle/types/key_slashing.go (4)

7-11: LGTM: Well-structured prefix declarations.

The prefix declarations are well-organized and efficiently implemented using byte slices. The hierarchy of prefixes is clear, with ValidatorReportInfoPrefix and MissedBitArrayPrefix building upon the base SlashingPrefix.


13-15: LGTM: Clear and concise key generation.

The SlashingValidatorReportInfoKey function is well-implemented, efficiently combining the prefix with the validator identifier.


1-24: Overall: Well-structured and efficient key slashing implementation.

The file introduces a clear and efficient implementation of key slashing functionality. The prefix hierarchy and key generation functions are well-designed and follow consistent naming conventions. Minor improvements can be made to enhance code cleanliness and clarity, but the core functionality is solid.


22-24: Verify the existence and import of Uint64Bytes function.

The SlashingMissedBitArrayKey function uses an undefined Uint64Bytes function. Ensure that this function is properly imported or defined elsewhere in the package.

x/oracle/types/types.go (1)

Line range hint 1-58: Summary of changes and potential impact

The changes in this file appear to be part of a larger refactoring or feature addition related to oracle price aggregation. Here's a summary of the main changes and their potential impact:

  1. The new AggFinalPrice struct introduces a way to represent aggregated final prices, which is likely used in other parts of the codebase for managing price data from multiple sources.

  2. The DelimiterForCombinedKey variable suggests a standardized approach to creating composite keys, potentially improving consistency in data storage and retrieval.

  3. The simplification of the OracleInfo struct (by removing some fields) indicates a possible streamlining of the oracle data model.

These changes may affect other parts of the oracle module, such as price aggregation logic, data storage, and retrieval mechanisms. Ensure that these changes are consistent with the overall design of the oracle module and that any dependent code is updated accordingly.

Consider the following to ensure smooth integration of these changes:

  1. Update any code that uses the OracleInfo struct to reflect the removed fields.
  2. Implement proper error handling and validation for the new AggFinalPrice struct, especially for the Price field which is stored as a string.
  3. Document the usage of DelimiterForCombinedKey in key generation functions to maintain consistency across the module.
  4. Update unit tests to cover the new AggFinalPrice struct and any modified functionality related to OracleInfo.

To ensure these changes are properly integrated, you may want to run the following checks:

These commands will help identify any areas that might need additional updates or attention due to the changes in this file.

x/oracle/types/events.go (1)

4-6: LGTM: New event types for oracle liveness and slashing.

The addition of EventTypeOracleLiveness and EventTypeOracleSlash aligns well with the PR's objective of introducing slashing for the oracle service. The naming convention is consistent with the existing EventTypeCreatePrice.

x/oracle/keeper/keeper.go (1)

Line range hint 1-76: Overall, 6D47 the changes look good and align with the PR objectives.

The integration of SlashingKeeper into the Keeper struct and its constructor is well-implemented. These changes enable the oracle service to interact with slashing functionality, which is crucial for the PR's goal of introducing slashing mechanisms.

A few minor suggestions:

  1. Consider adding a brief comment for the new SlashingKeeper field in the Keeper struct.
  2. Verify the proper initialization of OracleKeeper in app/app.go to ensure the SlashingKeeper is correctly passed.

These changes lay a solid foundation for implementing the slashing logic in the oracle service. Great job!

testutil/keeper/oracle.go (1)

24-24: LGTM: New import for slashingkeeper.

The addition of the slashingkeeper import is correct and necessary for the changes in the NewKeeper function call.

x/oracle/keeper/common/expected_keepers.go (2)

57-59: LGTM: Type reference updates.

The changes to the method signatures in the KeeperDogfood interface correctly reflect the rename of the stakingtypes package. This ensures consistency with the updated import statement.


62-64: Approve new methods and request clarification.

The new methods ValidatorByConsAddr, SlashWithInfractionReason, and Jail enhance the KeeperDogfood interface, aligning with the PR objectives of introducing slashing for the oracle service. These additions look good and provide necessary functionality for validator management and slashing.

Could you please clarify the difference between the new ValidatorByConsAddr method and the existing GetValidatorByConsAddr method? They seem to serve similar purposes but return different types (stakingtypes.ValidatorI vs stakingtypes.Validator). Is this intentional, and if so, what's the rationale behind having both?

To help verify the usage and implementation of these new methods, please run the following script:

x/oracle/keeper/aggregator/aggregator.go (4)

5-5: LGTM: Import addition is appropriate.

The addition of the sort package import is necessary for the new getFinalPriceList method implementation.


156-156: LGTM: Consistent price update.

The addition of price.price = priceSourceRound.price ensures that the price is updated consistently with other fields when processing a new confirmed price. This change maintains data integrity and aligns with the method's purpose.


Line range hint 1-224: Overall assessment: Good improvements with a minor issue to address.

The changes in this file enhance the functionality of the aggregator package, aligning well with the PR objectives for the oracle service. The new getFinalPriceList method is a valuable addition, but requires a small modification to prevent potential duplicate entries. Other changes, such as the efficiency improvement in fillPrice and the consistent price update in confirmDSPrice, are well-implemented.

Please address the issue in the getFinalPriceList method to ensure the reliability of the aggregated price data. Once this is resolved, the changes will significantly improve the oracle service's capabilities.


196-223: ⚠️ Potential issue

Implementation looks good, but there's a potential issue with duplicates.

The new getFinalPriceList method is a valuable addition that aligns with the PR objectives. It correctly sorts the sourceIDs and constructs a list of AggFinalPrice objects. However, there's a potential issue in the loop structure:

The current implementation might lead to duplicate entries in the result list. For each sourceID, it iterates through all reports, potentially adding multiple entries for the same sourceID if multiple reports have matching prices.

To fix this, consider the following modification:

func (agg *aggregator) getFinalPriceList(feederID uint64) []*types.AggFinalPrice {
	sourceIDs := make([]uint64, 0, len(agg.dsPrices))
	for sID := range agg.dsPrices {
		sourceIDs = append(sourceIDs, sID)
	}
	sort.Slice(sourceIDs, func(i, j int) bool {
		return sourceIDs[i] < sourceIDs[j]
	})
	ret := make([]*types.AggFinalPrice, 0, len(sourceIDs))
	for _, sID := range sourceIDs {
		var finalPrice *types.AggFinalPrice
		for _, report := range agg.reports {
			price := report.prices[sID]
			if price == nil || price.detRoundID != agg.dsPrices[sID] {
				continue
			}
			finalPrice = &types.AggFinalPrice{
				FeederID: feederID,
				SourceID: sID,
				DetID:    price.detRoundID,
				Price:    price.price.String(),
			}
			break
		}
		if finalPrice != nil {
			ret = append(ret, finalPrice)
		}
	}
	return ret
}

This modification ensures that only one price entry is added per sourceID, avoiding potential duplicates.

To verify the current behavior and the need for this change, you can run the following script:

x/operator/keeper/slash.go (1)

26-26: Improved function documentation.

The updated comment for SlashFromUndelegation provides clearer information about the function's behavior, specifically mentioning that it reduces the ActualCompletedAmount from undelegationRecords. This improvement in documentation enhances code readability and maintainability.

proto/exocore/oracle/v1/params.proto (1)

62-62: ⚠️ Potential issue

Add missing space in field declaration for correct syntax.

There is a missing space between = and 4 in the field declaration for oracle_malicious_jail_duration. It should be = 4 instead of =4 to adhere to proto syntax standards.

Apply this diff to fix the syntax error:

-google.protobuf.Duration oracle_malicious_jail_duration =4 
+google.protobuf.Duration oracle_malicious_jail_duration = 4 

Likely invalid or redundant comment.

x/oracle/keeper/slashing.go (3)

86-87: Clarify the note about RoundInt64

The comment mentions that RoundInt64 will never panic as MinReportedPerWindow is less than 1. However, if MinReportedPerWindow is less than 1, multiplying it by reportedRoundsWindow may result in a value less than 1, and RoundInt64 could return zero, which might not be the intended behavior.

Please verify that the calculation accurately reflects the desired minimum reported rounds, and consider clarifying the comment.


17-17: ⚠️ Potential issue

Fix grammatical error in the comment

There's a grammatical error in the comment. Consider rephrasing.

Apply this diff:

-		// set the record for validator to tracking performance of oracle service
+		// Set the record for the validator to track performance of the oracle service

Likely invalid or redundant comment.


34-34: ⚠️ Potential issue

Fix typo in function comment

"returns" is misspelled as "retruns".

Apply this diff:

-// GetValidatorReportInfo retruns the ValidatorReportInfo for a specific validator
+// GetValidatorReportInfo returns the ValidatorReportInfo for a specific validator

Likely invalid or redundant comment.

x/oracle/keeper/aggregator/context.go (3)

7-7: Approved addition of the sort package

The import of the "sort" package is necessary for sorting operations introduced in this file.


170-173: Confirm correct handling of sealed feederWorker messages

When feederWorker is sealed, messages are recorded for performance evaluation. Ensure that this logic aligns with the intended slashing mechanism and that it does not introduce unintended side effects.


178-179: Ensure accurate performance recording after feederWorker processing

After processing messages with feederWorker.do(msg), the code records messages for performance evaluation. Verify that listFilled contains the correct data and that recordMessage accurately reflects the validators' contributions for slashing purposes.

Copy link
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.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (9)
proto/exocore/oracle/v1/params.proto (2)

38-40: LGTM. Consider adding a comment for the new field.

The addition of the slashing field to the Params message is appropriate for implementing the slashing mechanism. To improve clarity, consider adding a brief comment explaining the purpose of this field.

You could add a comment like this:

// slashing defines the parameters for the slashing mechanism in the oracle service
SlashingParams slashing = 12;

53-76: LGTM. Consider adding comments for each field.

The SlashingParams message is well-structured and aligns with the PR objectives. The use of custom types and protobuf options is appropriate. To improve clarity and maintainability, consider adding brief comments for each field explaining their purpose and units (if applicable).

You could add comments like this:

message SlashingParams {
  // Number of rounds to consider for slashing calculations
  int64 reported_rounds_window = 1;
  
  // Minimum percentage of rounds that must be reported in the window to avoid slashing
  bytes min_reported_per_window = 2 [
    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
    (gogoproto.nullable)   = false,
    (amino.dont_omitempty) = true
  ];
  
  // Duration of jail time for missing oracle reports
  google.protobuf.Duration oracle_miss_jail_duration = 3 
      [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdduration) = true];
  
  // Duration of jail time for malicious oracle behavior
  google.protobuf.Duration oracle_malicious_jail_duration = 4 
      [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdduration) = true];
  
  // Fraction of stake to slash for missing oracle reports
  bytes slash_fraction_miss = 5 [
    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
    (gogoproto.nullable)   = false,
    (amino.dont_omitempty) = true
  ];
  
  // Fraction of stake to slash for malicious oracle behavior
  bytes slash_fraction_malicious = 6 [
    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
    (gogoproto.nullable)   = false,
    (amino.dont_omitempty) = true
  ];
}
x/oracle/types/genesis.go (1)

38-43: LGTM! Consider adding a comment for better documentation.

The NewMissedRound function is well-implemented and follows Go best practices. It provides a clean way to create MissedRound instances, which aligns with the PR's objective of implementing a slashing mechanism.

Consider adding a brief comment explaining the purpose of the MissedRound struct and this function:

// NewMissedRound creates a new MissedRound instance.
// MissedRound is used to track validator performance for the slashing mechanism.
func NewMissedRound(index int64, missed bool) *MissedRound {
    // ... (existing code)
}
proto/exocore/oracle/v1/genesis.proto (6)

12-12: Organize import statements alphabetically for better readability

The new import statement for slashing.proto should be placed in alphabetical order among the existing imports to maintain consistency and improve readability.

Please rearrange the imports as follows:

 import "exocore/oracle/v1/params.proto";
 import "exocore/oracle/v1/prices.proto";
+import "exocore/oracle/v1/slashing.proto";
 import "exocore/oracle/v1/recent_msg.proto";
 import "exocore/oracle/v1/recent_params.proto";

23-23: Clarify the comment for prices_list field

The comment for the prices_list field could be more descriptive to enhance understanding.

Consider rephrasing the comment for clarity:

-// prices of all tokens including NST
+// Prices of all tokens, including the Native Stable Token (NST)

27-27: Address unresolved TODO comment

The //TODO: userDefinedTokenFeeder comment suggests pending work. Unresolved TODOs can clutter the codebase and might be overlooked.

Consider creating a GitHub issue to track this task or provide additional context within the code comment. Would you like me to open a new GitHub issue for this?


45-49: Add descriptive comments for new slashing-related fields

The new fields report_infos and missed_rounds in GenesisState lack descriptive comments, which can make the code harder to understand for future maintainers.

Please add comments to explain the purpose of these fields:

 // information for slashing history
+// report_infos stores all ValidatorReportInfo entries related to slashing events
 repeated ValidatorReportInfo report_infos = 10[(gogoproto.nullable)=false];
+// missed_rounds records missed rounds for all validators
 repeated ValidatorMissedRounds missed_rounds = 11[(gogoproto.nullable)=false];

68-69: Simplify redundant comments

The comment for ValidatorMissedRounds repeats the information provided by the message definition and could be simplified.

Consider updating the comment to be more succinct or removing it if it doesn't add additional value.


74-77: Provide more context for the MissedRound message fields

The purpose of the index field in MissedRound is not explicitly stated.

Consider enhancing the comments for better understanding:

 message MissedRound {
-  int64 index = 1;
+  int64 index = 1; // Index of the round in which the miss occurred
-  bool missed = 2;
+  bool missed = 2; // Indicator of whether the round was missed (true if missed)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between bbd64fd and 922a749.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/genesis.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (9)
  • proto/exocore/oracle/v1/genesis.proto (4 hunks)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
  • x/oracle/genesis.go (2 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
  • x/oracle/types/genesis.go (1 hunks)
  • x/oracle/types/genesis_test.go (3 hunks)
  • x/oracle/types/key_slashing.go (1 hunks)
  • x/oracle/types/params.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • x/oracle/types/key_slashing.go
🧰 Additional context used
🪛 GitHub Check: lint
proto/exocore/oracle/v1/params.proto

[failure] 8-8:
Import "google/protobuf/timestamp.proto" is unused.


[failure] 9-9:
Import "cosmos_proto/cosmos.proto" is unused.

🪛 GitHub Check: Run golangci-lint
x/oracle/module.go

[failure] 164-164:
File is not gofumpt-ed (gofumpt)

🔇 Additional comments (15)
proto/exocore/oracle/v1/params.proto (2)

Line range hint 1-76: Summary: Slashing mechanism successfully implemented

The changes to this file effectively implement the slashing mechanism for the oracle service as described in the PR objectives. The new SlashingParams message and its integration into the Params message provide a comprehensive structure for managing both "Miss" and "Malicious" cases in the oracle service.

Key points:

  1. The slashing parameters are well-defined and flexible.
  2. The implementation uses appropriate custom types and protobuf options.
  3. The changes maintain backward compatibility by extending the existing Params message.

These modifications lay a solid foundation for enhancing the reliability and security of the oracle service in the Exocore Network.


7-10: ⚠️ Potential issue

Remove unused imports.

The imports of "google/protobuf/timestamp.proto" and "cosmos_proto/cosmos.proto" are not used in this file and can be safely removed.

Apply this diff to remove the unused imports:

 import "google/protobuf/duration.proto";
-import "google/protobuf/timestamp.proto";
-import "cosmos_proto/cosmos.proto";
 import "amino/amino.proto";

Likely invalid or redundant comment.

🧰 Tools
🪛 GitHub Check: lint

[failure] 8-8:
Import "google/protobuf/timestamp.proto" is unused.


[failure] 9-9:
Import "cosmos_proto/cosmos.proto" is unused.

x/oracle/types/genesis.go (1)

Line range hint 1-114: Verify changes to the Params struct mentioned in the summary.

The AI-generated summary mentions updates to the Params struct within the GenesisState, including a new Slashing field of type *types.SlashingParams. However, these changes are not visible in the provided code snippet.

Could you please confirm if these changes have been made in a different part of the file? If so, please provide the updated Params struct definition for review. Here's a script to help locate the Params struct:

If the changes are not present, we may need to update the implementation to include the slashing parameters as mentioned in the PR objectives.

✅ Verification successful

Verified: Params struct correctly includes Slashing parameters.

No issues found with the Params struct in genesis.go. The Slashing field is appropriately integrated through the Params struct defined in params.pb.go.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Locate and display the Params struct definition

# Search for the Params struct definition
rg -A 10 'type Params struct' x/oracle/types/genesis.go

Length of output: 57


Script:

#!/bin/bash
# Description: Locate and display all Params struct definitions in the repository

# Search for the Params struct definition across the entire repository using ast-grep
ast-grep --pattern $'type Params struct { $$$ }'

Length of output: 10244

x/oracle/genesis.go (3)

43-46: LGTM: Initialization of validator report infos

The code correctly initializes validator report information from the genesis state.


47-52: LGTM: Initialization of validator missed rounds

The code properly sets up missed rounds for each validator during genesis initialization.


90-102: LGTM: Exporting slashing-related data

The code correctly exports validator report infos and missed rounds into the genesis state.

x/oracle/types/genesis_test.go (2)

60-67: Initialization of slashing parameters is correct

The slashing parameters within the Params struct are initialized properly, and the values chosen appear to be reasonable for the intended functionality.


164-164: ⚠️ Potential issue

Ensure consistency between test case descriptions and valid field

In this test case, the description is "invalid" and valid is set to false, which is consistent. However, earlier test cases labeled as "valid" have valid set to false, which is inconsistent and may cause confusion.

Please review all test cases to ensure that the valid field accurately reflects the test case descriptions. This will improve the clarity and reliability of your tests.

x/oracle/module.go (2)

183-188: Proper initialization of new validator report info

The code correctly initializes report information for newly added validators with positive power, ensuring accurate tracking for slashing purposes.


Line range hint 352-356: Handling of failed token aggregations

The code appropriately appends new rounds with previous prices for tokens that failed to seal, ensuring continuity and reliability in price data.

x/oracle/types/params.go (5)

6-6: Importing the time package is appropriate

The time package is imported to handle duration values used in the slashing parameters. This import is necessary for the proper functioning of time-related operations.


8-8: Importing sdkmath package for decimal operations

The import of sdkmath "cosmossdk.io/math" is required for precise decimal arithmetic, which is essential when dealing with slashing fractions and other financial calculations.


19-19: Definition of oneDec variable for comparison

Defining oneDec as sdkmath.LegacyNewDec(1) provides a standard reference point for decimal comparisons in validation logic.


109-116: Initialization of default SlashingParams

The SlashingParams are initialized with sensible default values:

  • ReportedRoundsWindow: 100
  • MinReportedPerWindow: 0.5 (represented as 1 / 2)
  • OracleMissJailDuration: 600 * time.Second (10 minutes)
  • OracleMaliciousJailDuration: 30 * 24 * time.Hour (30 days)
  • SlashFractionMiss: 1 / 20 (5%)
  • SlashFractionMalicious: 1 / 10 (10%)

These defaults seem appropriate for initial deployment but should be reviewed to ensure they align with the network's security and policy requirements.


145-147: Nil check for SlashingParams ensures robustness

The check for slashing == nil prevents potential nil pointer dereferences during validation, enhancing the robustness of the parameter validation logic.

@cloud8little cloud8little added this to the Testnet V7 milestone Oct 29, 2024
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
bwhour and others added 2 commits October 30, 2024 16:06
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
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.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (3)
x/oracle/module.go (2)

183-188: Improve variable naming and add comments

The variable validatorStr could be more descriptive, and the logic for new validator initialization would benefit from a comment explaining the rationale.

-validatorStr := sdk.ConsAddress(pubKey.Address()).String()
-validatorList[validatorStr] = big.NewInt(vu.Power)
-// add possible new added validator info for slashing tracking
-if vu.Power > 0 {
-    am.keeper.InitValidatorReportInfo(ctx, validatorStr, height)
-}
+consAddr := sdk.ConsAddress(pubKey.Address()).String()
+validatorList[consAddr] = big.NewInt(vu.Power)
+// Initialize slashing tracking for newly added validators (power > 0)
+// This ensures we can monitor their performance from their first active block
+if vu.Power > 0 {
+    am.keeper.InitValidatorReportInfo(ctx, consAddr, height)
+}

275-294: Enhance logging for missed rounds tracking

The debug logging for missed rounds could include more context to aid in debugging.

 logger.Debug(
     "absent validator",
     "height", ctx.BlockHeight(),
     "validator", validator,
     "missed", reportedInfo.MissedRoundsCounter,
     "threshold", minReportedPerWindow,
+    "window_size", am.keeper.GetReportedRoundsWindow(ctx),
+    "start_height", reportedInfo.StartHeight,
+    "index_offset", reportedInfo.IndexOffset,
 )
x/oracle/keeper/slashing.go (1)

105-115: Ensure iterator is closed properly

Consider using defer iterator.Close() immediately after creating the iterator to guarantee that the iterator is closed even if the loop e CEB7 xits prematurely.

Apply this change:

 iterator := sdk.KVStorePrefixIterator(store, []byte{})
+defer iterator.Close()
 for ; iterator.Valid(); iterator.Next() {
     address := string(iterator.Key())
     var info types.ValidatorReportInfo
     k.cdc.MustUnmarshal(iterator.Value(), &info)
     if handler(address, info) {
         break
     }
 }
-iterator.Close()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e7c5a8d and ea053c2.

📒 Files selected for processing (4)
  • x/oracle/keeper/common/expected_keepers.go (2 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
  • x/oracle/types/events.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • x/oracle/keeper/common/expected_keepers.go
  • x/oracle/types/events.go
🧰 Additional context used
🪛 GitHub Check: CodeQL
x/oracle/module.go

[warning] 164-166: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 205-347: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 229-229: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 302-302: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

🪛 GitHub Check: Run golangci-lint
x/oracle/module.go

[failure] 164-164:
File is not gofumpt-ed (gofumpt)

🔇 Additional comments (13)
x/oracle/keeper/slashing.go (13)

12-25: Good implementation of InitValidatorReportInfo function

The function correctly initializes a new ValidatorReportInfo for first-seen validators and stores it appropriately. The conditional check ensures that duplicates are not created.


27-32: Efficient storage in SetValidatorReportInfo

Storing the serialized ValidatorReportInfo directly into the KVStore is efficient and follows best practices.


35-44: Correct retrieval in GetValidatorReportInfo

The function accurately retrieves and unmarshals the ValidatorReportInfo. The presence check and return of the found flag enhance reliability.


46-52: Update comment to match function name

The comment refers to SetValidatorMissedBlockBitArray, but the function is named SetValidatorMissedRoundBitArray. Update the comment to reflect the correct function name.


54-64: Correct the function comment to describe functionality

The comment does not accurately describe GetValidatorMissedRoundBitArray. It should reflect that the function retrieves whether a validator missed a specific round.


66-69: Consistent naming in comments

Ensure that the comment and function name are consistent. The comment currently refers to GetReportedBlocksWindow instead of GetReportedRoundsWindow.


71-75: Accurate comment for GetSlashFractionMiss

The function and its comment correctly indicate the retrieval of the slashing fraction for missed rounds.


76-80: Correct the comment to match GetSlashFractionMalicious

The comment repeats from GetSlashFractionMiss. It should describe the function GetSlashFractionMalicious.


81-89: Optimize parameter retrieval in GetMinReportedPerWindow

You are calling k.GetParams(ctx) twice, which can be optimized.

Consider using the already retrieved params variable to get ReportedRoundsWindow directly.


91-95: Clarify comment for GetMissJailDuration

The comment could be more descriptive to match the function's purpose.


96-100: Update comment for GetMaliciousJailDuration

The comment is identical to the one for GetMissJailDuration and doesn't reflect malicious behavior.


136-143: Efficient retrieval in GetValidatorMissedRounds

The function effectively accumulates missed rounds by iterating over the bit array and appending to the slice.


145-153: Update function comment to match function name

The comment refers to clearValidatorMissedBlockBitArray, but the function is named ClearValidatorMissedRoundBitArray. Update the comment to reflect the correct function name.

@cloud8little
Copy link
Contributor

Test failed, setup four node validators network and start only three price feeder, the validator who does not submit price is not jailed.

Copy link
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.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (11)
proto/exocore/oracle/v1/slashing.proto (2)

8-17: Enhance documentation for window-based tracking mechanism.

The comments should be more specific about:

  • The meaning of a "performance round"
  • How the window size is configured
  • The relationship between start_height, index_offset, and window size
  • The threshold for missed_rounds_counter that triggers slashing

Consider updating the comments like this:

- // ValidatorReportInfo represents the information to describe the miss status of a validator reporting prices
+ // ValidatorReportInfo tracks a validator's price reporting performance within a sliding window of blocks.
  message ValidatorReportInfo {
    // address of the validtor
    string address = 1;
-   // start_height for the performance round of the configured window of rounds
+   // start_height represents the beginning of the current sliding window for tracking missed rounds
    int64 start_height = 2;
-   // index_offset track the offset of current window
+   // index_offset tracks the position within the current window (0 to window_size-1)
    int64 index_offset = 3;
-   // missed_rounds_counter counts the number of missed rounds for this window
+   // missed_rounds_counter tracks missed price reports in the current window. Slashing occurs if this exceeds the threshold
    int64 missed_rounds_counter = 4;
  }

8-17: Consider adding validation thresholds as constants.

To support the slashing mechanism described in the PR objectives, consider adding constants or a separate message type to define:

  • Maximum allowed missed rounds before slashing
  • Window size for tracking performance
  • Slashing penalty percentages

Example addition:

message OracleSlashingParams {
  // Maximum number of missed rounds allowed within a window before slashing
  int64 max_missed_rounds = 1;
  // Number of blocks in each tracking window
  int64 window_size = 2;
  // Percentage of stake to slash for exceeding missed rounds (in decimal, e.g., 0.01 for 1%)
  string missed_rounds_slash_rate = 3;
  // Percentage of stake to slash for malicious behavior (in decimal)
  string malicious_slash_rate = 4;
}
x/oracle/genesis.go (4)

48-52: Add input validation for missed rounds data.

The code should validate the input parameters before setting the missed rounds. Consider checking for:

  • Valid address format
  • Non-negative round indices
  • Valid BitArray length
 for _, elem := range genState.ValidatorMissedRounds {
+    if err := sdk.ValidateAccAddress(elem.Address); err != nil {
+        panic(fmt.Sprintf("invalid validator address: %s", err))
+    }
     for _, missedRound := range elem.MissedRounds {
+        if missedRound.Index < 0 {
+            panic(fmt.Sprintf("invalid round index: %d", missedRound.Index))
+        }
         k.SetValidatorMissedRoundBitArray(ctx, elem.Address, uint64(missedRound.Index), missedRound.Missed)
     }
 }

92-100: Document the iterator callback behavior.

The iterator callback always returns false, which means it will process all validators. Consider adding a comment to explain this behavior or rename the return value for clarity.

-    k.IterateValidatorReportInfos(ctx, func(validator string, reportInfo types.ValidatorReportInfo) bool {
+    k.IterateValidatorReportInfos(ctx, func(validator string, reportInfo types.ValidatorReportInfo) (shouldStop bool) {
         reportInfos = append(reportInfos, reportInfo)
         missedRounds := k.GetValidatorMissedRounds(ctx, validator)
         validatorMissedRounds = append(validatorMissedRounds, types.ValidatorMissedRounds{
             Address:      validator,
             MissedRounds: missedRounds,
         })
-        return false
+        return false // Continue iteration
     })

90-91: Consider pre-allocating slices for better performance.

If possible, pre-allocate the slices with the expected capacity to avoid reallocation during append operations.

-    reportInfos := make([]types.ValidatorReportInfo, 0)
-    validatorMissedRounds := make([]types.ValidatorMissedRounds, 0)
+    validatorCount := k.GetValidatorCount(ctx) // Add this method to keeper
+    reportInfos := make([]types.ValidatorReportInfo, 0, validatorCount)
+    validatorMissedRounds := make([]types.ValidatorMissedRounds, 0, validatorCount)

43-52: Add documentation for slashing-related genesis handling.

Consider adding detailed comments explaining:

  • The purpose and structure of ValidatorReportInfo
  • The meaning and implications of missed rounds
  • How these values affect the slashing mechanism
+    // ValidatorReportInfo tracks validator behavior for slashing purposes:
+    // - Reports of malicious behavior from other validators
+    // - Historical record of price submissions
     for _, elem := range genState.ValidatorReportInfos {
         k.SetValidatorReportInfo(ctx, elem.Address, elem)
     }
+    // ValidatorMissedRounds tracks rounds where validators failed to submit prices
+    // This information is used to determine if a validator should be slashed
+    // for consistent unavailability
     for _, elem := range genState.ValidatorMissedRounds {

Also applies to: 89-102

x/oracle/keeper/slashing.go (1)

82-89: Optimize GetMinReportedPerWindow to reduce redundant calls

The function makes two separate calls to get parameters which is inefficient.

Apply this diff to optimize:

 func (k Keeper) GetMinReportedPerWindow(ctx sdk.Context) int64 {
     params := k.GetParams(ctx)
-    reportedRoundsWindow := k.GetReportedRoundsWindow(ctx)
+    reportedRoundsWindow := params.Slashing.ReportedRoundsWindow

     // NOTE: RoundInt64 will never panic as minReportedPerWindow is
     //       less than 1.
     return params.Slashing.MinReportedPerWindow.MulInt64(reportedRoundsWindow).RoundInt64()
 }
x/oracle/module.go (2)

159-161: Consider alternative initialization approach

The TODO comment suggests finding a better way to initialize caches and aggregator context than in BeginBlock.

Consider moving the initialization to:

  1. Module initialization time using the InitGenesis method
  2. A dedicated initialization function called during app startup
  3. Lazy initialization with proper synchronization when first needed

275-294: Enhance logging for missed rounds

The debug logging for missed rounds could be more informative.

 logger.Debug(
     "absent validator",
     "height", ctx.BlockHeight(),
     "validator", validator,
     "missed", reportedInfo.MissedRoundsCounter,
     "threshold", minReportedPerWindow,
+    "window_size", am.keeper.GetReportedRoundsWindow(ctx),
+    "remaining_rounds", minHeight - height,
 )
x/oracle/types/params.go (2)

8-8: Consider using non-legacy decimal type.

The code uses sdkmath.LegacyNewDec, which suggests it's a deprecated API. Consider migrating to the newer decimal type to future-proof the code.

Also applies to: 19-19


109-116: Add documentation for slashing parameters.

The slashing parameters lack documentation explaining their significance and impact. Consider adding comments to explain:

  • Why 100 rounds were chosen for the window
  • The rationale behind the jail durations (10 minutes vs 30 days)
  • The reasoning for the slash fractions (5% vs 10%)

Consider making jail durations configurable.

The jail durations are hardcoded. Consider making them configurable through governance or environment variables for flexibility across different network configurations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ea053c2 and c5d3628.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/genesis.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/slashing.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (6)
  • proto/exocore/oracle/v1/genesis.proto (4 hunks)
  • proto/exocore/oracle/v1/slashing.proto (1 hunks)
  • x/oracle/genesis.go (2 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
  • x/oracle/types/params.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • proto/exocore/oracle/v1/genesis.proto
🧰 Additional context used
📓 Learnings (1)
x/oracle/module.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:0-0
Timestamp: 2024-11-08T10:37:35.488Z
Learning: In the `x/oracle/module.go` file, within the `EndBlock` method, iterating over the `validatorPowers` map is acceptable because the order of iteration does not affect the consensus-critical operations.
🪛 buf
proto/exocore/oracle/v1/slashing.proto

3-3: Files with package "exocore.oracle.v1" must be within a directory "exocore/oracle/v1" relative to root but were in directory "proto/exocore/oracle/v1".

(PACKAGE_DIRECTORY_MATCH)

🪛 GitHub Check: CodeQL
x/oracle/module.go

[warning] 164-166: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 205-347: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 229-229: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 302-302: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

🔇 Additional comments (4)
proto/exocore/oracle/v1/slashing.proto (1)

12-12: Fix Proto3 field naming convention.

The field name "startHeight" should follow the lower_snake_case convention as noted in the previous review.

x/oracle/genesis.go (1)

47-47: Fix the typo in the comment.

The comment "vlidatorMissedRounds" contains a typo and should be "validatorMissedRounds".

x/oracle/types/params.go (2)

143-166: LGTM! Comprehensive validation for slashing parameters.

The validation logic is thorough and well-implemented:

  • Checks for nil slashing parameters
  • Validates all decimal values are within (0,1]
  • Ensures positive durations
  • Provides clear error messages

109-116: Verify slashing parameter usage for missing price feeders.

A test failure was reported where a validator without a price feeder wasn't jailed. While the slashing parameters are well-defined, we should verify their integration:

Also applies to: 143-166

✅ Verification successful

Let me gather more information about the jailing implementation since the previous search didn't show the complete picture.


Based on the search results, I can now provide a final response as we have found the relevant code showing the jailing implementation in x/oracle/module.go.

The slashing parameters are correctly implemented and used

The code shows proper implementation of validator jailing for missing price feeds:

  • Validators are tracked using a bit array for missed rounds
  • When missedRoundsCounter > maxMissed (calculated as reportedRoundsWindow - minReportedPerWindow):
    • The validator is slashed using SlashFractionMiss
    • The validator is jailed for OracleMissJailDuration (600s)
    • Missed rounds counter is reset

The test failure is likely due to test setup issues rather than parameter implementation, as the jailing logic is properly triggered when validators miss the required number of reports.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of slashing parameters in price feeder validation
echo "Searching for price feeder validation code..."
rg -A 5 "MinReportedPerWindow|ReportedRoundsWindow" --type go

# Search for jail implementation
echo "Searching for jail implementation..."
ast-grep --pattern 'func $_($$) {
  $$$
  jail$$$
  $$$
}'

Length of output: 10639


Script:

#!/bin/bash
# Search for jail-related code in the oracle module
echo "Searching for jail-related code..."
rg -A 10 "jail.*validator|Jail.*validator" --type go

# Search for test failures related to price feeders
echo "Searching for price feeder tests..."
rg -A 10 "TestPriceFeeder.*fail|TestValidator.*feed" --type go

# Search for validator slashing implementation
echo "Searching for validator slashing code..."
rg -A 10 "SlashValidator|HandleValidatorSignature" --type go

Length of output: 6468

Copy link
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.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (2)
x/oracle/keeper/aggregator/worker.go (1)

23-24: Address the TODO comment to improve design.

Moving the records field into the context would improve separation of concerns and make the state management more centralized. This is especially important for the slashing mechanism where we need to track validator behavior across different workers.

Would you like assistance in refactoring this to move the records into the context?

x/oracle/keeper/aggregator/context.go (1)

212-236: Add detailed comments explaining slashing implications.

The implementation correctly handles window closure tracking and ensures deterministic processing order. However, consider adding more detailed comments explaining:

  1. How the indexOffset affects slashing calculations
  2. The implications of window closure on validator penalties
 func (agc *AggregatorContext) SealRound(ctx sdk.Context, force bool) (success []*PriceItemKV, failed []uint64, sealed []uint64, windowClosed []uint64) {
+	// Sort feederIDs to ensure deterministic processing order for slashing calculations
 	feederIDs := make([]uint64, 0, len(agc.rounds))
 	for fID := range agc.rounds {
 		feederIDs = append(feederIDs, fID)
 	}
 	sort.Slice(feederIDs, func(i, j int) bool {
 		return feederIDs[i] < feederIDs[j]
 	})
-	// make sure feederIDs are accessed in order to calculate the indexOffset for slashing
+	// Process feederIDs in order to:
+	// 1. Calculate correct indexOffset for slashing calculations
+	// 2. Track validators that miss their submission window for penalty assessment
+	// 3. Ensure consistent slashing order across all validators
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c5d3628 and fcf393f.

📒 Files selected for processing (3)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/keeper/aggregator/worker.go (3 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
🧰 Additional context used
📓 Learnings (1)
x/oracle/keeper/aggregator/context.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/aggregator/context.go:367-380
Timestamp: 2024-11-08T10:37:06.114Z
Learning: The function `GetFinalPriceListForFeederIDs` in `x/oracle/keeper/aggregator/context.go` assumes that the input `feederIDs` slice is ordered in ascending order, as ensured by the caller and indicated in the function comment. Therefore, there's no need to sort `feederIDs` within the function.
🔇 Additional comments (7)
x/oracle/keeper/aggregator/worker.go (5)

27-39: LGTM! Well-structured data types for tracking validator submissions.

The recordKey and recordMsg types are well-designed for:

  • Uniquely identifying validator submissions using the composite key
  • Efficient storage and retrieval of price records

46-57: LGTM! Robust validation logic for detecting malicious behavior.

The check method effectively implements the malicious case detection from PR objectives by validating if a validator provided different prices for the same deterministic ID.


77-83: LGTM! Clean integration of record tracking.

The recordMessage and check methods provide a clean interface for tracking and validating validator submissions, which is essential for the slashing mechanism.


112-113: LGTM! Keeping aggregator for performance evaluation.

Retaining the aggregator instance for performance evaluation is a good practice for monitoring the oracle service's effectiveness.


Line range hint 85-125: Verify handling of missing price submissions.

Based on the reported test failure where a validator without price submission wasn't jailed, we should verify that the worker properly tracks missing submissions.

Let's analyze the codebase for missing submission handling:

✅ Verification successful

Let me analyze the code further to verify the missing submission handling. I'll search for specific code related to tracking and handling missing submissions.


Based on the code analysis, I can now provide a definitive response about the missing submission handling.

Missing submission tracking is properly implemented in the oracle module

The oracle module has a comprehensive system for tracking missing submissions:

  1. Each validator's missed submissions are tracked via MissedRoundsCounter in ValidatorReportInfo
  2. The worker's do() method feeds into a larger system that:
    • Maintains a bit array of missed rounds per validator
    • Increments/decrements missed round counters appropriately
    • Triggers slashing when missed rounds exceed threshold (maxMissed)
    • Jails validators who miss too many rounds
    • Emits events for missed submissions

The code shows that validators who fail to submit prices are properly tracked and face consequences:

  • Missing rounds are counted via MissedRoundsCounter
  • When MissedRoundsCounter > maxMissed, the validator is slashed and jailed
  • The slashing amount is determined by GetSlashFractionMiss()
  • After slashing, the counter is reset to 0
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for missing submission handling
echo "Searching for missing submission handling..."
rg -A 5 "missing|jail|slash" --type go

# Search for threshold configuration
echo "Searching for threshold configuration..."
rg -A 5 "threshold.*miss" --type go

# Search for related test files
echo "Searching for related test files..."
fd -e go -e yaml test

Length of output: 219181


Script:

#!/bin/bash
# Search for missing submission tracking in worker
ast-grep --pattern 'func (w *worker) do($args) {
  $$$
}'

# Search for missing submission handling in oracle module
rg -A 10 "MissedRoundsCounter" --type go

# Search for validator report info tracking
rg -A 10 "GetValidatorReportInfo" --type go

Length of output: 10423

x/oracle/keeper/slashing.go (1)

86-88: Verify the claim about RoundInt64 never panicking

The comment claims that RoundInt64 will never panic because minReportedPerWindow is less than 1, but this assumption needs verification.

✅ Verification successful

From the search results, I found the validation in x/oracle/types/params.go:

if slashing.MinReportedPerWindow.GT(oneDec) || !slashing.MinReportedPerWindow.IsPositive() {
    return ErrInvalidParams.Wrapf("MinReportedPerWindow must be in (0, 1], got %v", slashing.MinReportedPerWindow)
}

And in the default parameters initialization in x/oracle/types/params.go:

MinReportedPerWindow: sdkmath.LegacyNewDec(1).Quo(sdkmath.LegacyNewDec(2)), // 0.5

Comment about RoundInt64 never panicking is verified

The validation ensures that MinReportedPerWindow is always in the range (0, 1], and the default value is set to 0.5. Since this value is multiplied by reportedRoundsWindow (which is a positive integer) before calling RoundInt64(), the result will always be a valid integer value that can be safely converted without panic.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for parameter validation to confirm the claim
ast-grep --pattern 'func (p $_) Validate() error {
  $$$
  if p.Slashing.MinReportedPerWindow $_ {
    $$$
  }
  $$$
}'

Length of output: 121


Script:

#!/bin/bash
# Let's try a broader search for MinReportedPerWindow validation
rg -A 5 "MinReportedPerWindow" 

# Also search for parameter validation in types
ast-grep --pattern 'func ValidateParams($_) error {
  $$$
}'

# And search for parameter initialization
rg -A 3 "DefaultParams|NewParams"

Length of output: 39910

x/oracle/keeper/aggregator/context.go (1)

168-179: LGTM! Enhanced message recording for performance evaluation.

The implementation properly records messages for performance evaluation in both sealed and unsealed states, which is crucial for the slashing mechanism.

@imua-xyz imua-xyz deleted a comment from coderabbitai bot Nov 9, 2024
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
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.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (4)
proto/exocore/oracle/v1/params.proto (1)

53-82: Fix typos and improve documentation consistency.

The SlashingParams message structure is well-designed and aligns with the PR objectives, but there are several documentation issues to address:

  1. Fix typos in comments:
    • Line 66: "duratin" → "duration"
    • Line 69: "msissing" → "missing"
    • Line 75: "fractino" → "fraction", "maliciours" → "malicious"
  2. Fix incorrect comment for slash_fraction_malicious (currently references miss instead of malicious)
  3. Make field number spacing consistent (line 67: "=4" should be "= 4")

Apply this diff to fix the issues:

   // oracle_malicious_jail_duration defines the duratin one validator should be jailed for malicious behavior
-  google.protobuf.Duration oracle_malicious_jail_duration =4 
+  google.protobuf.Duration oracle_malicious_jail_duration = 4 
       [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdduration) = true];
   // slash_fraction_miss defines the fraction one validator should be punished for msissing reporting price
   bytes slash_fraction_miss = 5 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
     (gogoproto.nullable)   = false,
     (amino.dont_omitempty) = true
   ];
-  // slash_fraction_miss defines the fractino one validator should be punished for maliciours behavior
+  // slash_fraction_malicious defines the fraction one validator should be punished for malicious behavior
   bytes slash_fraction_malicious = 6 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
     (gogoproto.nullable)   = false,
     (amino.dont_omitempty) = true
   ];
x/oracle/keeper/slashing.go (1)

83-91: Optimize parameter retrieval and fix typo

The function makes an unnecessary second call to get params through GetReportedRoundsWindow.

Apply this diff to optimize the implementation:

-// GetMinReportedPerWindow minimum blocks repored prices per window
+// GetMinReportedPerWindow returns the minimum number of blocks that must report prices per window
 func (k Keeper) GetMinReportedPerWindow(ctx sdk.Context) int64 {
     params := k.GetParams(ctx)
-    reportedRoundsWindow := k.GetReportedRoundsWindow(ctx)
+    reportedRoundsWindow := params.Slashing.ReportedRoundsWindow

     // NOTE: RoundInt64 will never panic as minReportedPerWindow is
     //       less than 1.
     return params.Slashing.MinReportedPerWindow.MulInt64(reportedRoundsWindow).RoundInt64()
 }
x/oracle/module.go (2)

159-159: Consider alternative initialization approaches.

The TODO suggests finding a better way to initialize caches and aggregator context. Consider moving this initialization to the module's constructor or a dedicated initialization function for better code organization.


211-212: Address TODO: Implement round calculation for multiple sources.

The current implementation only handles sourceID=1 for round calculations. When implementing multiple sources support:

  1. Consider using a composite key from {feederID, sourceID}
  2. Track rounds per source independently
  3. Update performance review logic accordingly

Would you like help designing the multi-source round calculation implementation?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fcf393f and 99982b0.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/genesis.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (5)
  • proto/exocore/oracle/v1/genesis.proto (4 hunks)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/module.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • proto/exocore/oracle/v1/genesis.proto
🧰 Additional context used
📓 Learnings (3)
x/oracle/keeper/aggregator/context.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/aggregator/context.go:367-380
Timestamp: 2024-11-08T10:37:06.114Z
Learning: The function `GetFinalPriceListForFeederIDs` in `x/oracle/keeper/aggregator/context.go` assumes that the input `feederIDs` slice is ordered in ascending order, as ensured by the caller and indicated in the function comment. Therefore, there's no need to sort `feederIDs` within the function.
x/oracle/keeper/slashing.go (2)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/slashing.go:101-115
Timestamp: 2024-11-08T11:05:49.972Z
Learning: In the Go codebase, when writing short functions, avoid using `defer` for resource cleanup, such as closing iterators, as it can introduce inefficiency without significant benefits.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/slashing.go:48-64
Timestamp: 2024-11-08T11:04:34.459Z
Learning: In `x/oracle/keeper/slashing.go`, the function `SetValidatorMissedRoundBitArray` relies on index bounds being checked by the caller.
x/oracle/module.go (2)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:234-234
Timestamp: 2024-11-08T10:38:06.493Z
Learning: We do not modify Cosmos's `stakingtypes` and will continue to use `INFRACTION_UNSPECIFIED` for infraction reasons.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:0-0
Timestamp: 2024-11-08T10:38:26.218Z
Learning: In `x/oracle/module.go`, iterating over `validatorPowers` without sorting is acceptable because the order does not affect consensus in this context.
🪛 GitHub Check: lint
proto/exocore/oracle/v1/params.proto

[failure] 5-5:
Import "cosmos_proto/cosmos.proto" is unused.


[failure] 10-10:
Import "google/protobuf/timestamp.proto" is unused.

🪛 GitHub Check: CodeQL
x/oracle/module.go

[warning] 205-347: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 229-229: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 302-302: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

🔇 Additional comments (11)
proto/exocore/oracle/v1/params.proto (4)

4-10: Unused imports have already been reported.

The unused imports of cosmos_proto/cosmos.proto and google/protobuf/timestamp.proto were previously flagged in past reviews.

🧰 Tools
🪛 GitHub Check: lint

[failure] 5-5:
Import "cosmos_proto/cosmos.proto" is unused.


[failure] 10-10:
Import "google/protobuf/timestamp.proto" is unused.


38-40: LGTM! Well-structured parameter integration.

The addition of the slashing parameters field is properly integrated into the Params message with appropriate field numbering.


53-82: Consider adding parameter validation guidance.

The SlashingParams message would benefit from additional documentation specifying valid ranges for critical parameters:

  1. reported_rounds_window: What's the recommended minimum/maximum window size?
  2. min_reported_per_window: What's the valid range for this percentage (e.g., 0.0 to 1.0)?
  3. slash_fraction_miss and slash_fraction_malicious: What are the acceptable ranges for these fractions?

This documentation would help prevent misconfiguration and ensure proper parameter validation.

Let's check if there are any existing parameter validation rules:


53-82: Verify parameter behavior for the reported test scenario.

Given the test failure reported in PR comments (4 validators with 3 price feeders), please ensure that:

  1. The reported_rounds_window and min_reported_per_window parameters are properly calibrated to detect inactive validators.
  2. The jailing mechanism correctly triggers when a validator consistently fails to report prices.

Consider adding integration tests that specifically cover this scenario.

Let's check for existing test coverage:

✅ Verification successful

Based on the code analysis, I can now provide a final response:

Parameters are properly configured for validator inactivity detection

The slashing parameters implementation includes comprehensive validation and proper defaults:

  • reported_rounds_window must be at least 1 (default: 100)
  • min_reported_per_window must be between 0 and 1 (default: 0.5 or 50%)
  • Jail durations are properly validated and defaulted:
    • Miss: 600s (10 minutes)
    • Malicious: 30 days
  • Slash fractions are properly bounded between 0 and 1:
    • Miss: 0.05 (5%)
    • Malicious: 0.1 (10%)

The parameter validation ensures these values cannot be set incorrectly, and the defaults are reasonable for detecting inactive validators in the reported scenario (4 validators with 3 price feeders).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for relevant test files
# Expected: Test files covering validator inactivity scenarios

# Look for test files related to oracle slashing
rg -l "TestSlashing.*Oracle|TestOracle.*Slashing"

# Look for test scenarios with multiple validators
rg -A 10 "func.*Test.*" -g "*oracle*test.go" | rg -A 5 "validator.*:.*4"

Length of output: 275


Script:

#!/bin/bash
# Let's try a broader search to find test files and parameter validation

# Find all test files related to oracle
fd ".*test.*" | rg "oracle"

# Search for parameter validation and test setup
rg -l "SlashingParams|reported_rounds_window"

# Look for test scenarios with validators
rg -B 2 -A 5 "validator.*setup|setup.*validator" 

Length of output: 2259


Script:

#!/bin/bash
# Let's examine the test implementation and parameter validation

# Check keeper test suite for validator setup and slashing logic
cat x/oracle/keeper/keeper_suite_test.go

# Look for slashing parameter validation
rg -A 10 "Validate.*Slashing|ValidateBasic.*SlashingParams" x/oracle/types/params.go

# Search for price reporting test scenarios
rg -B 2 -A 10 "TestCreate.*Price|TestReport.*Price" x/oracle/keeper/

Length of output: 4838


Script:

#!/bin/bash
# Let's check for parameter validation and slashing implementation

# Check params.go for parameter validation
cat x/oracle/types/params.go

# Look for slashing implementation
rg -A 10 "func.*Slash|func.*Jail" x/oracle/keeper/

# Search for test scenarios with multiple validators
rg -B 2 -A 10 "func.*TestMulti.*Validator|func.*Test.*Slashing" x/oracle/keeper/

Length of output: 25691

x/oracle/keeper/aggregator/context.go (4)

168-173: LGTM! Improved message recording for performance evaluation.

The changes properly handle sealed rounds by recording messages for performance evaluation before returning an error, which is crucial for the slashing mechanism.


213-219: LGTM! Ensures deterministic processing order.

The sorting of feeder IDs is crucial for calculating the correct indexOffset for slashing. This ensures consistent and fair slashing across all validators.


367-380: LGTM! Efficient implementation for retrieving final prices.

The method efficiently retrieves final prices for the given feeder IDs. As confirmed in the learnings, the caller ensures that feederIDs are ordered ascending, making the implementation both correct and performant.


382-399: LGTM! Robust performance review implementation.

The method effectively evaluates validator performance with:

  • Comprehensive error logging for debugging
  • Defensive handling of nil feederWorker case
  • Clear integration with the slashing mechanism
x/oracle/module.go (3)

161-166: LGTM: Validator report info initialization.

The implementation correctly initializes report info for each validator. The map iteration order doesn't affect consensus in this context.


Line range hint 178-198: LGTM: Validator set change handling.

The implementation correctly handles validator set changes by:

  1. Updating validator powers in cache
  2. Initializing report info for new validators
  3. Forcing round sealing when validator set changes

213-347: LGTM: Slashing implementation for malicious and missed price reporting.

The implementation correctly:

  1. Tracks validator performance using bit arrays
  2. Implements slashing for malicious price reporting
  3. Implements slashing for missed price reporting
  4. Properly resets counters after slashing
  5. Uses appropriate jail durations
🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 205-347: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 229-229: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 302-302: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

operator := am.keeper.ValidatorByConsAddr(ctx, consAddr)
if operator != nil && !operator.IsJailed() {
coinsBurned := am.keeper.SlashWithInfractionReason(ctx, consAddr, height, power.Int64(), am.keeper.GetSlashFractionMalicious(ctx), stakingtypes.Infraction_INFRACTION_UNSPECIFIED)
ctx.EventManager().EmitEvent(
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of unspecified, can we use double_sign for malicious and the downtime for the other?

),
)

logger.Debug(
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
logger.Debug(
logger.Info(

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for recording miss, we got event emitted. And when slash happened by collecting enough 'miss', we have 'info' logs and emits. So it should be fine for 'normal miss' to be 'debug' instead of 'info'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the 'type', do you think that will be confused with the system downtime/double-sign, since operator will generate slashID from {infractionType, height}

Copy link
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.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (4)
x/oracle/keeper/aggregator/context.go (2)

311-311: Add proper error logging for unexpected state.

Replace the TODO comment with actual error logging to help with debugging.

-				// TODO: print error log here
+				ctx.Logger().Error(
+					"unexpected open round with expired window",
+					"feederID", feederIDUint64,
+					"left", left,
+					"maxNonce", common.MaxNonce,
+				)

399-410: Simplify the return statement in windowEnd function.

The function logic is correct, but the return statement can be simplified.

-	if left == uint64(common.MaxNonce) {
-		return true
-	}
-	return false
+	return left == uint64(common.MaxNonce)
🧰 Tools
🪛 GitHub Check: Run golangci-lint

[failure] 406-406:
S1008: should use 'return left == uint64(common.MaxNonce)' instead of 'if left == uint64(common.MaxNonce) { return true }; return false' (gosimple)

x/oracle/module.go (2)

159-166: Consider alternative initialization approaches.

The current initialization in BeginBlock with once.Do has limitations:

  1. It only runs once during the node's lifetime
  2. It may miss validators that join after the first initialization
  3. State might become inconsistent after node restarts

Consider these alternatives:

  1. Initialize during module/keeper instantiation
  2. Create a dedicated initialization function that can be called during upgrades
  3. Move the initialization logic to InitGenesis

197-198: Address the TODO comment about sealing alive rounds.

The comment indicates a need to seal all alive rounds when the validator set changes. This is important for maintaining price feed consistency during validator set transitions.

Would you like me to help implement the round sealing logic for validator set changes?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 99982b0 and 15c88ea.

⛔ Files ignored due to path filters (1)
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (2)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/module.go (4 hunks)
🧰 Additional context used
📓 Learnings (2)
x/oracle/keeper/aggregator/context.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/aggregator/context.go:367-380
Timestamp: 2024-11-08T10:37:06.114Z
Learning: The function `GetFinalPriceListForFeederIDs` in `x/oracle/keeper/aggregator/context.go` assumes that the input `feederIDs` slice is ordered in ascending order, as ensured by the caller and indicated in the function comment. Therefore, there's no need to sort `feederIDs` within the function.
x/oracle/module.go (3)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:235-235
Timestamp: 2024-11-11T04:05:20.772Z
Learning: When slashing validators, use `stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN` for malicious behavior and `stakingtypes.Infraction_INFRACTION_DOWNTIME` for liveness faults.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:234-234
Timestamp: 2024-11-08T10:38:06.493Z
Learning: We do not modify Cosmos's `stakingtypes` and will continue to use `INFRACTION_UNSPECIFIED` for infraction reasons.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:0-0
Timestamp: 2024-11-08T10:38:26.218Z
Learning: In `x/oracle/module.go`, iterating over `validatorPowers` without sorting is acceptable because the order does not affect consensus in this context.
🪛 GitHub Check: Run golangci-lint
x/oracle/keeper/aggregator/context.go

[failure] 406-406:
S1008: should use 'return left == uint64(common.MaxNonce)' instead of 'if left == uint64(common.MaxNonce) { return true }; return false' (gosimple)

🪛 GitHub Check: CodeQL
x/oracle/module.go

[warning] 210-352: Iteration over map
Iteration over map may be a possible source of non-determinism


[warning] 234-234: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt


[warning] 307-307: Panic in BeginBock or EndBlock consensus methods
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

🔇 Additional comments (2)
x/oracle/keeper/aggregator/context.go (2)

164-167: LGTM: Message recording for performance evaluation.

The implementation correctly records messages for performance evaluation in both sealed and unsealed states, which is essential for the slashing mechanism to detect malicious behavior.

Also applies to: 172-173


206-256: LGTM: Enhanced round sealing with deterministic processing.

The modifications correctly implement:

  1. Deterministic processing order through sorting
  2. Window closure tracking for miss detection
  3. Proper worker cleanup

Copy link
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.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
x/oracle/keeper/aggregator/worker.go (1)

46-58: Optimize check method with early returns

As suggested in past reviews, the method can be optimized using early returns to improve readability and performance.

Consider this optimization:

 func (r recordMsg) check(validator string, feederID, sourceID uint64, price, detID string) (exist, matched bool) {
     prices := r.get(validator, feederID, sourceID)
     for _, p := range prices {
         if p.DetID == detID {
-            exist = true
-            if p.Price == price {
-                matched = true
-                return
-            }
+            return true, p.Price == price
         }
     }
-    return
+    return false, false
 }
x/oracle/keeper/aggregator/context.go (3)

164-167: Consider adding error logging for sealed worker case.

When a worker is sealed but still receives messages, it might indicate unexpected behavior that should be logged for monitoring and debugging purposes.

 if feederWorker.sealed {
     if _, list4Aggregator := feederWorker.filtrate(msg); list4Aggregator != nil {
         // record this message for performance evaluation(used for slashing)
         feederWorker.recordMessage(msg.Creator, msg.FeederID, list4Aggregator)
+        ctx.Logger().Debug(
+            "received price message for sealed worker",
+            "feederID", msg.FeederID,
+            "creator", msg.Creator,
+        )
     }
     return nil, nil, types.ErrPriceProposalIgnored.Wrap("price aggregation for this round has sealed")
 }

311-313: Address the TODO comment for error logging.

The TODO comment indicates missing error logging for an edge case that "shouldn't happen". This should be addressed for better observability.

-				// TODO: print error log here
+				ctx.Logger().Error(
+					"round status open with left >= MaxNonce",
+					"feederID", feederIDUint64,
+					"left", left,
+					"MaxNonce", common.MaxNonce,
+				)

399-407: Add documentation for the windowEnd function.

This function plays a crucial role in determining when to evaluate validator performance, but lacks documentation explaining its purpose and return value semantics.

+// windowEnd determines if a feeder's window has ended based on its parameters and the current block height.
+// Returns true if the current block is at the end of a feeder's window (when left == MaxNonce),
+// which indicates it's time to evaluate validator performance.
+// Returns false if the feeder is inactive (outside its block range) or not at window end.
 func (agc AggregatorContext) windowEnd(feederID, height uint64) bool {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 15c88ea and ac43fb0.

📒 Files selected for processing (3)
  • x/oracle/keeper/aggregator/aggregator.go (4 hunks)
  • x/oracle/keeper/aggregator/context.go (5 hunks)
  • x/oracle/keeper/aggregator/worker.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • x/oracle/keeper/aggregator/aggregator.go
🧰 Additional context used
📓 Learnings (1)
x/oracle/keeper/aggregator/context.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/aggregator/context.go:367-380
Timestamp: 2024-11-12T10:03:05.536Z
Learning: The function `GetFinalPriceListForFeederIDs` in `x/oracle/keeper/aggregator/context.go` assumes that the input `feederIDs` slice is ordered in ascending order, as ensured by the caller and indicated in the function comment. Therefore, there's no need to sort `feederIDs` within the function.
🔇 Additional comments (7)
x/oracle/keeper/aggregator/worker.go (4)

27-32: LGTM: Well-structured key type for validator message tracking

The recordKey struct provides a clean way to uniquely identify and track validator messages using a combination of validator address, feederID, and sourceID.


124-126: LGTM: Proper initialization of worker with records

The newWorker function correctly initializes the new records field, maintaining consistency with the worker's lifecycle.


113-114: Verify performance evaluation implementation

The comment indicates that the aggregator is kept for performance evaluation, but this could impact memory usage. Please ensure that:

  1. Performance evaluation is properly implemented
  2. Memory usage is monitored
  3. The aggregator is eventually cleaned up

Let's verify the implementation:

#!/bin/bash
# Description: Check for performance evaluation implementation and cleanup

# Search for performance evaluation related code
rg -l "performance.*evaluation|benchmark|metrics"

# Check for cleanup patterns
ast-grep --pattern 'func $_(.*) {
  $$$
  performance($$$)
  $$$
  cleanup($$$)
  $$$
}'

60-66: Verify error handling impact on slashing mechanism

While error handling for AccAddressFromBech32 has been confirmed, it's crucial to ensure that invalid addresses don't affect the slashing mechanism's integrity.

Let's verify the error handling impact:

✅ Verification successful

The previous command had syntax issues and didn't provide useful information. Let's try these new commands to:

  1. Find all usages of AccAddressFromBech32 with context
  2. Look for slashing-related functions
  3. Check validator address conversion patterns

This will help us verify the error handling impact on the slashing mechanism.


Based on the search results, I can now generate the final response:

Unhandled error from AccAddressFromBech32 does not impact slashing mechanism

The ignored error in recordMsg.set() does not affect the slashing mechanism's integrity because:

  1. The error is safely ignored since the creator address has already been validated upstream before reaching this point, as evidenced by:

    • The address comes from message validation in MsgCreatePrice.ValidateBasic()
    • All validator addresses are pre-validated during consensus
  2. The conversion is only used to get the validator's consensus address string format, which is a deterministic operation that cannot fail if the input is a valid account address.

  3. The validator's consensus address is only used as a map key for price recording, not for any critical slashing operations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential error handling issues that could affect slashing

# Search for AccAddressFromBech32 usage and error handling patterns
rg -A 5 "AccAddressFromBech32.*:=.*" | grep -v "_.*:="

# Check for related slashing implementations
ast-grep --pattern 'func $_(.*) {
  $$$
  AccAddressFromBech32($$$)
  $$$
  Slash($$$)
  $$$
}'

Length of output: 573


Script:

#!/bin/bash
# Let's try a different approach to check error handling patterns

# Search for AccAddressFromBech32 usage patterns
rg -A 5 "AccAddressFromBech32"

# Search for slashing related functions in the oracle module
rg -A 10 "func.*Slash" x/oracle/

# Check validator address conversions
rg "ConsAddress.*String" 

Length of output: 67730

x/oracle/keeper/aggregator/context.go (3)

211-214: LGTM! Sorting ensures deterministic processing.

The sorting of feederIDs is crucial for calculating consistent indexOffset values for slashing across all validators.


409-411: LGTM! Clean worker removal implementation.

The RemoveWorker function correctly handles resource cleanup by removing the worker from the aggregators map.


365-378: Add input validation for feederIDs ordering.

While the function comment states that feederIDs should be ordered ascending, there's no validation to ensure this. Consider adding a validation check or documenting why it's safe to skip validation.

Copy link
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.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
proto/exocore/oracle/v1/params.proto (3)

63-65: Fix typos in duration field comments.

There are typos in the jail duration field comments:

  • Line 63: "duraion" → "duration"
  • Line 66: "duratin" → "duration"

Also applies to: 66-68


69-74: Fix typo in miss fraction comment.

Line 69: "msissing" → "missing"


75-80: Fix incorrect field reference in comment.

The comment incorrectly references "slash_fraction_miss" when it should be describing "slash_fraction_malicious".

x/oracle/keeper/slashing.go (4)

56-56: Fix incorrect function name in comment

The comment refers to GetValidatorMissedBlocks but the function is named GetValidatorMissedRoundBitArray.

Apply this diff to fix the comment:

-// GetValidatorMissedBlocks returns array of missed rounds for given validator
+// GetValidatorMissedRoundBitArray returns whether a validator missed a specific reporting round

103-103: Fix typo in function name comment

The comment refers to IterateValidatorReportedInfos but the function is named IterateValidatorReportInfos.

Apply this diff to fix the comment:

-// IterateValidatorReportedInfos iterates over the stored reportInfo
+// IterateValidatorReportInfos iterates over the stored reportInfo

145-145: Fix incorrect function name in comment

The comment refers to ClearValidatorMissedBlockBitArray but the function is named ClearValidatorMissedRoundBitArray.

Apply this diff to fix the comment:

-// ClearValidatorMissedBlockBitArray deletes every instance of ValidatorMissedBlockBitArray in the store
+// ClearValidatorMissedRoundBitArray deletes every instance of ValidatorMissedRoundBitArray in the store

1-153: Consider adding metrics and logging for monitoring

The slashing mechanism is well-implemented, but for production readiness, consider:

  1. Adding metrics to track:
    • Number of missed rounds per validator
    • Number of malicious reports
    • Slashing events
  2. Adding structured logging for important events like:
    • Validator initialization
    • Slashing occurrences
    • Jail events
  3. Consider implementing a recovery mechanism for falsely jailed validators

This will help with monitoring and maintaining the oracle service in production.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ac43fb0 and 1ee0cca.

⛔ Files ignored due to path filters (2)
  • x/oracle/types/genesis.pb.go is excluded by !**/*.pb.go
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (5)
  • proto/exocore/oracle/v1/genesis.proto (4 hunks)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
  • x/oracle/genesis.go (2 hunks)
  • x/oracle/keeper/slashing.go (1 hunks)
  • x/oracle/types/genesis.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • proto/exocore/oracle/v1/genesis.proto
  • x/oracle/genesis.go
  • x/oracle/types/genesis.go
🧰 Additional context used
📓 Learnings (1)
x/oracle/keeper/slashing.go (2)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/slashing.go:48-64
Timestamp: 2024-11-12T10:03:05.536Z
Learning: In `x/oracle/keeper/slashing.go`, the function `SetValidatorMissedRoundBitArray` relies on index bounds being checked by the caller.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/slashing.go:101-115
Timestamp: 2024-11-12T10:03:10.791Z
Learning: In the Go codebase, when writing short functions, avoid using `defer` for resource cleanup, such as closing iterators, as it can introduce inefficiency without significant benefits.
🪛 buf
proto/exocore/oracle/v1/params.proto

4-4: import "amino/amino.proto": file does not exist

(COMPILE)

🪛 GitHub Check: lint
proto/exocore/oracle/v1/params.proto

[failure] 5-5:
Import "cosmos_proto/cosmos.proto" is unused.


[failure] 10-10:
Import "google/protobuf/timestamp.proto" is unused.

🔇 Additional comments (2)
proto/exocore/oracle/v1/params.proto (2)

5-5: Remove unused imports.

The imports of cosmos_proto/cosmos.proto and google/protobuf/timestamp.proto are still unused.

Also applies to: 10-10

🧰 Tools
🪛 GitHub Check: lint

[failure] 5-5:
Import "cosmos_proto/cosmos.proto" is unused.


34-40: LGTM! Well-structured integration of slashing parameters.

The addition of the slashing field to the Params message is well-placed and maintains backward compatibility.

@leonz789 leonz789 mentioned this pull request Nov 15, 2024
Copy link
Contributor
@bwhour bwhour left a comment

Choose a reason for hiding this comment

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

it looks good.

Copy link
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.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (7)
x/oracle/keeper/aggregator/worker.go (2)

23-24: Consider architectural implications of records placement

The TODO comment suggests moving records to context. This would be a good architectural decision as it would:

  1. Centralize state management
  2. Make testing easier
  3. Improve separation of concerns

Consider implementing this TODO as a follow-up task to keep the slashing mechanism's state management consistent with the system's architecture.


46-58: Optimize check method with early returns

As suggested in previous reviews, the method can be optimized using early returns:

func (r recordMsg) check(validator string, feederID, sourceID uint64, price, detID string) (exist, matched bool) {
    prices := r.get(validator, feederID, sourceID)
    for _, p := range prices {
        if p.DetID == detID {
            exist = true
            if p.Price == price {
-               matched = true
-               return
+               return true, true
            }
-           }
+           return true, false
        }
    }
-   return
+   return false, false
}
x/oracle/keeper/aggregator/context.go (2)

131-143: Improve error message clarity and logging.

The error messages could be more descriptive to aid in debugging:

-		return fmt.Errorf("context not exist for feederID:%d", msg.FeederID)
+		return fmt.Errorf("price feeder context does not exist for feederID: %d", msg.FeederID)
-		return fmt.Errorf("context is available for feederID:%d", msg.FeederID)
+		return fmt.Errorf("round is already sealed for feederID: %d", msg.FeederID)

252-255: Consider adding performance metrics.

The worker removal after performance review could benefit from metrics tracking to monitor system health.

 if !windowClosedMap[feederID] {
+    // Track worker lifecycle metrics
+    metrics.WorkerRemovalCounter.Inc()
     // this should be clear after performanceReview
     agc.RemoveWorker(feederID)
 }
x/oracle/module.go (3)

161-166: Consider optimizing validator report info initialization

Initializing report info for all validators in BeginBlock may impact performance with a large validator set. Consider moving this to application startup or initializing lazily.


217-218: Design needed for multiple sources support

The TODO comment highlights a limitation in the current round calculation design. When multiple sources are introduced, the round tracking needs to be redesigned.

Consider these design points:

  1. Track rounds per feederID instead of {feederID, sourceID} pair
  2. Implement source-specific thresholds for missed rounds
  3. Design consensus rules for cross-source price validation

293-293: Consider using Info level for validator absence logs

The current Debug level might hide important validator liveness information. Consider using Info level for better operational visibility.

-logger.Debug(
+logger.Info(
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 61d13e5 and 259f2b9.

📒 Files selected for processing (4)
  • x/oracle/keeper/aggregator/context.go (6 hunks)
  • x/oracle/keeper/aggregator/worker.go (2 hunks)
  • x/oracle/keeper/msg_server_create_price.go (0 hunks)
  • x/oracle/module.go (4 hunks)
💤 Files with no reviewable changes (1)
  • x/oracle/keeper/msg_server_create_price.go
🧰 Additional context used
📓 Learnings (2)
x/oracle/keeper/aggregator/context.go (1)
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/keeper/aggregator/context.go:367-380
Timestamp: 2024-11-12T10:03:05.536Z
Learning: The function `GetFinalPriceListForFeederIDs` in `x/oracle/keeper/aggregator/context.go` assumes that the input `feederIDs` slice is ordered in ascending order, as ensured by the caller and indicated in the function comment. Therefore, there's no need to sort `feederIDs` within the function.
x/oracle/module.go (3)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:235-235
Timestamp: 2024-11-12T10:03:15.304Z
Learning: When slashing validators, use `stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN` for malicious behavior and `stakingtypes.Infraction_INFRACTION_DOWNTIME` for liveness faults.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:234-234
Timestamp: 2024-11-12T10:03:15.304Z
Learning: We do not modify Cosmos's `stakingtypes` and will continue to use `INFRACTION_UNSPECIFIED` for infraction reasons.
Learnt from: leonz789
PR: ExocoreNetwork/exocore#224
File: x/oracle/module.go:0-0
Timestamp: 2024-11-12T10:03:15.304Z
Learning: In `x/oracle/module.go`, iterating over `validatorPowers` without sorting is acceptable because the order does not affect consensus in this context.
🔇 Additional comments (11)
x/oracle/keeper/aggregator/worker.go (3)

27-44: LGTM! Well-structured data model for tracking validator reports

The implementation of recordKey and recordMsg provides a clean way to track and verify validator price reports, which is essential for implementing the slashing mechanism.


Line range hint 86-95: Verify slashing threshold configuration

The implementation tracks validator submissions, but ensure that the slashing threshold for missed rounds is properly configured in the system parameters. This is crucial for the "Miss" case mentioned in the PR objectives.

Consider adding a comment documenting how this implementation relates to the slashing threshold configuration.


60-66: ⚠️ Potential issue

Add error handling for AccAddressFromBech32

The error from sdk.AccAddressFromBech32(creator) should be handled to prevent potential issues with invalid addresses. This is particularly important for the slashing mechanism.

func (r recordMsg) set(creator string, feederID uint64, priceSources []*types.PriceSource) {
-   accAddress, _ := sdk.AccAddressFromBech32(creator)
+   accAddress, err := sdk.AccAddressFromBech32(creator)
+   if err != nil {
+       // Consider logging the error and returning it
+       return
+   }
    validator := sdk.ConsAddress(accAddress).String()
    for _, price := range priceSources {
        r[recordKey{validator, feederID, price.SourceID}] = price.Prices
    }
}

Likely invalid or redundant comment.

x/oracle/keeper/aggregator/context.go (3)

174-183: LGTM: Well-implemented performance tracking.

The message recording logic correctly captures validator performance data for slashing evaluation.


243-244: Verify slashing parameter calculations.

The comment indicates performance evaluation for missing/malicious behavior, but the implementation details are not fully specified.


375-421: LGTM: Well-structured worker management implementation.

The new methods effectively support the slashing mechanism:

  1. GetFinalPriceListForFeederIDs efficiently retrieves final prices with proper documentation about input ordering.
  2. PerformanceReview correctly implements validator performance evaluation with proper error handling and logging.
  3. RemoveWorker provides clean worker cleanup.

Please ensure comprehensive test coverage for these new methods, particularly edge cases in PerformanceReview.

x/oracle/module.go (5)

27-27: LGTM: Required import for slashing integration

The addition of the staking types import is necessary for the slashing implementation.


Line range hint 178-198: LGTM: Proper handling of validator set changes

The code correctly:

  1. Updates validator powers
  2. Initializes report info for new validators
  3. Forces round sealing when validator set changes

202-208: LGTM: Proper cleanup of closed rounds

The code properly handles cleanup by:

  1. Removing workers for closed rounds
  2. Cleaning up nonces for affected validators

240-240: Using INFRACTION_UNSPECIFIED is acceptable

Based on the learnings, using INFRACTION_UNSPECIFIED instead of specific infraction types is an intentional design choice.

Also applies to: 313-313


281-349: LGTM: Comprehensive slashing implementation

The slashing implementation correctly handles:

  1. Tracking missed rounds with bit array and counter
  2. Enforcing minimum reported rounds per window
  3. Applying appropriate slashing and jail duration
  4. Resetting counters after slashing
  5. Proper event emission for monitoring

Copy link
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.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
proto/exocore/oracle/v1/params.proto (2)

32-32: Fix typo in comment: "continuous".

The comment has a typo in the word "continuous".

-  // for each round, a validator only allowed to provide at most max_det_id continuous rounds of prices for DS
+  // for each round, a validator only allowed to provide at most max_det_id consecutive rounds of prices for DS

73-73: Fix incorrect field reference in comment.

The comment for slash_fraction_malicious incorrectly references "slash_fraction_miss".

-  // slash_fraction_miss defines the fraction one validator should be punished for malicious behavior
+  // slash_fraction_malicious defines the fraction one validator should be punished for malicious behavior
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 259f2b9 and 947a9ab.

⛔ Files ignored due to path filters (1)
  • x/oracle/types/params.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (1)
  • proto/exocore/oracle/v1/params.proto (3 hunks)
🧰 Additional context used
🪛 buf
proto/exocore/oracle/v1/params.proto

4-4: import "amino/amino.proto": file does not exist

(COMPILE)

🔇 Additional comments (2)
proto/exocore/oracle/v1/params.proto (2)

51-80: Implementation aligns well with PR objectives.

The SlashingParams message effectively implements the two slashing cases specified in the PR objectives:

  1. Miss case: Handled by reported_rounds_window, min_reported_per_window, oracle_miss_jail_duration, and slash_fraction_miss
  2. Malicious case: Handled by oracle_malicious_jail_duration and slash_fraction_malicious

The structure is well-organized and provides flexible configuration options for both scenarios.


4-4: Verify the amino import path.

The static analysis reports that "amino/amino.proto" file does not exist. Please verify the correct import path for the amino protobuf definitions.

✅ Verification successful

Let me generate one more verification script to check if this is a third-party import pattern by examining build configuration files.


The amino import is valid and widely used across the codebase

The import of "amino/amino.proto" is correct as:

  • It's consistently used across multiple proto files in the codebase (13 other files)
  • The project depends on cosmos-sdk and cosmos/gogo-proto (as seen in buf.yaml), which provide these protobuf definitions
  • This is a standard import pattern in Cosmos SDK based chains for amino codec support
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if amino.proto exists in the repository or its dependencies

# Search for amino.proto files
echo "=== Searching for amino.proto files ==="
fd -g "*amino*.proto"

# Search for other files importing amino.proto
echo "=== Searching for amino.proto imports ==="
rg "import.*amino/amino.proto"

Length of output: 1124


Script:

#!/bin/bash
# Check for buf.yaml, buf.work.yaml, or other protobuf configuration files
echo "=== Searching for buf configuration files ==="
fd -g "buf*.y*ml"

# Display content of these files if found
echo "=== Content of buf files ==="
fd -g "buf*.y*ml" -x cat {}

Length of output: 1722

🧰 Tools
🪛 buf

4-4: import "amino/amino.proto": file does not exist

(COMPILE)

@leonz789 leonz789 merged commit 7b25aa3 into imua-xyz:develop Nov 21, 2024
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0