Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

trigger distribution on slash event #261

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

leonz789
Copy link
Contributor

@leonz789 leonz789 commented Dec 6, 2024

Description

Trigger fee(including minted coins) distribution on validator set change, which caused by:

  1. slash event
  2. epoch end

Notable Changes

  1. trigger distribution on both slash event and epoch end
  2. calculate the staker portions based on dogfood's assets not all living AVSs.

Closes #XXX

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced token allocation process with updated handling for slashing events.
    • Introduced new interfaces for minting parameters and asset verification checks.
    • Added a framework for managing operator hooks related to key management and slashing events.
    • New mock implementations for testing various keeper interfaces, improving testing capabilities.
    • Integrated minting parameters into the genesis state configuration.
  • Bug Fixes

    • Improved error handling in token allocation during slashing events.
  • Documentation

    • Expanded comments for clarity on the purpose and functionality of new hooks and methods.
  • Refactor

    • Streamlined the logic for token allocation and staker determination.
    • Adjusted sleep duration in end-to-end tests for faster unjailing of validators.

Copy link
Contributor

coderabbitai bot commented Dec 6, 2024

Walkthrough

The changes in this pull request enhance the ExocoreApp structure and its associated methods, particularly focusing on the integration of hooks for various keepers, including OperatorKeeper, EpochsKeeper, and DistrKeeper. The modifications also involve updates to the AllocateTokens function to accommodate slashing scenarios and the introduction of the OperatorHooksWrapper for handling operator-related events. Additionally, new interfaces for MintKeeper and AVSKeeper are introduced, expanding the expected functionalities of the module. Overall, these changes improve the modularity and extensibility of the application.

Changes

File Path Change Summary
app/app.go Updated ExocoreApp structure, added hooks for OperatorKeeper and EpochsKeeper, modified NewExocoreApp constructor to initialize new hooks and include ExomintKeeper and AVSManagerKeeper.
x/feedistribution/keeper/allocation.go Changed AllocateTokens method signature from totalPreviousPower int64 to isSlash bool, updated logic for handling slashing events, and refactored AllocateTokensToStakers for clarity.
x/feedistribution/keeper/impl_epoch_hooks.go Modified AfterEpochEnd method to call AllocateTokens(ctx, false) instead of using previous total power, expanded comments for clarity.
x/feedistribution/keeper/impl_operator_hooks.go Introduced OperatorHooksWrapper type implementing OperatorHooks interface, defined methods for operator key management and slashing events, added logging and error handling in AfterSlash.
x/feedistribution/keeper/keeper.go Added fields mintKeeper and avsKeeper to Keeper struct, updated NewKeeper method to initialize these fields.
x/feedistribution/types/expected_keepers.go Added new interfaces MintKeeper and AVSKeeper with methods for minting parameters and AVS checks, updated import statements.
proto/exocore/delegation/v1/query.proto Modified QueryAssociatedStakersByOperator method's signature for formatting, no functional changes.
testutil/keeper/feedistribute.go Enhanced testing capabilities by adding mock instances for mintKeeper and avsKeeper, updated internal logic to include these new dependencies.
x/feedistribution/testutil/expected_account_mock.go Added mock implementation for AccountKeeper interface, facilitating testing.
x/feedistribution/testutil/expected_avs_mock.go Added mock implementation for AVSKeeper interface, facilitating testing.
x/feedistribution/testutil/expected_bank_mock.go Added mock implementation for BankKeeper interface, facilitating testing.
x/feedistribution/testutil/expected_epochs_mock.go Added mock implementation for EpochsKeeper interface, facilitating testing.
x/feedistribution/testutil/expected_mint_mock.go Added mock implementation for MintKeeper interface, facilitating testing.
x/feedistribution/testutil/mock_test.go Introduced a new test file for generating mocks for several interfaces, including BankKeeper, EpochsKeeper, AccountKeeper, MintKeeper, and AVSKeeper.
testutil/network/genesis_data.go Added new import statements for epochtypes and exominttypes, initialized DefaultGenStateExoMint, and modified OracleMissJailDuration parameter.
testutil/network/util.go Added import for exominttypes, integrated exomint module into the genesis file initialization process.
tests/e2e/oracle/create_price.go Adjusted sleep duration in testSlashing function and removed debug print statement for cleaner logging.

Possibly related PRs

Suggested labels

C:Types

Suggested reviewers

  • cloud8little
  • trestinlsd
  • bwhour
  • mikebraver
  • TimmyExogenous
  • leonz789

Poem

🐇 In the code where rabbits play,
New hooks and keepers lead the way.
Tokens flow with a joyful cheer,
As epochs end, our path is clear.
With every change, we hop along,
In this code, we all belong! 🌟


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: 5

🧹 Outside diff range and nitpick comments (5)
x/feedistribution/keeper/allocation.go (1)

154-154: Improve clarity of error message

The error message "Skipping distribution for due to fail to generate avsAddr from chainID" is grammatically incorrect and may be confusing. Please rephrase it for clarity.

Apply this diff to improve the error message:

- logger.Error("Skipping distribution for due to fail to generate avsAddr from chainID", "chainID", ctx.ChainID())
+ logger.Error("Skipping distribution due to failure in generating avsAddress from chainID", "chainID", ctx.ChainID())
x/feedistribution/keeper/impl_epoch_hooks.go (2)

33-33: Remove commented-out code or provide justification

The line // previousTotalPower := wrapper.keeper.StakingKeeper.GetLastTotalPower(ctx) is commented out. If this code is no longer needed, consider removing it to keep the codebase clean. If you plan to use it in the future, please add a comment explaining why it is retained.


38-41: Fix typos and improve comment clarity

There are typos in the comments that may reduce readability. For example, "minited tokens" should be "minted tokens". Please correct these typos and consider rephrasing the comments for better clarity.

Apply this diff to fix typos and improve the comments:

- // at the end of an epoch we distribute all minted tokens for one epoch and left fees
- // here we have the temporary approach that we allocate minited tokens for next epoch then we can correctly
- // distribute those tokens based on potential slash event. And that should be ok since the amount of minited
- // token for each epoch is the same, so we just missed the very first epoch's minting.
+ // At the end of an epoch, we distribute all minted tokens and any remaining fees for that epoch.
+ // Currently, we have a temporary approach where we allocate minted tokens for the next epoch,
+ // allowing us to correctly distribute tokens based on potential slashing events.
+ // This is acceptable since the minted token amount per epoch is the same, so we only miss the very first epoch's minting.
x/feedistribution/keeper/impl_operator_hooks.go (1)

19-25: Consider implementing or documenting empty hook methods

The methods AfterOperatorKeySet, AfterOperatorKeyReplaced, and AfterOperatorKeyRemovalInitiated are currently empty. If they are intentionally left unimplemented, consider adding comments to explain why or if implementation is planned for the future.

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

45-46: LGTM! Consider updating module documentation.

The new parameters are properly added to the constructor. Since these represent significant new dependencies, ensure that the module's documentation (especially godocs) is updated to reflect these changes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 53e2162 and 21bab9d.

📒 Files selected for processing (6)
  • app/app.go (1 hunks)
  • x/feedistribution/keeper/allocation.go (2 hunks)
  • x/feedistribution/keeper/impl_epoch_hooks.go (1 hunks)
  • x/feedistribution/keeper/impl_operator_hooks.go (1 hunks)
  • x/feedistribution/keeper/keeper.go (3 hunks)
  • x/feedistribution/types/expected_keepers.go (2 hunks)
🧰 Additional context used
📓 Learnings (1)
x/feedistribution/types/expected_keepers.go (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore#220
File: x/avs/types/expected_keepers.go:47-48
Timestamp: 2024-11-12T10:03:10.791Z
Learning: Adding new methods to the `OperatorKeeper` interface in `x/avs/types/expected_keepers.go` is acceptable, even if there are other unmodifiable `OperatorKeeper` interfaces elsewhere, because interfaces can be extended without causing conflicts.
🔇 Additional comments (6)
x/feedistribution/keeper/allocation.go (1)

14-21: ⚠️ Potential issue

Verify all calls to AllocateTokens are updated to match the new signature

The AllocateTokens function now accepts a boolean parameter isSlash instead of totalPreviousPower int64. Please ensure that all invocations of this function throughout the codebase are updated to match the new signature to prevent compile-time errors.

Run the following script to locate all calls to AllocateTokens that may need updating:

✅ Verification successful

The previous ast-grep pattern might have failed due to syntax. Let's try with ripgrep to find all occurrences of AllocateTokens calls and its function definition to compare the signatures.


All calls to AllocateTokens are already updated with the new signature

The verification shows that all calls to AllocateTokens are correctly using the new boolean parameter:

  • In impl_operator_hooks.go: AllocateTokens(ctx, true)
  • In impl_epoch_hooks.go: AllocateTokens(ctx, false)

These match the new function signature defined in allocation.go: AllocateTokens(ctx sdk.Context, isSlash bool) error

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all occurrences of AllocateTokens calls that need updating.

ast-grep --pattern 'AllocateTokens($_)'

Length of output: 41


Script:

#!/bin/bash
# Search for AllocateTokens function calls with ripgrep for better coverage
rg "AllocateTokens\(" -A 2

# Also search for the function definition to understand the old signature
rg "func.*AllocateTokens"

Length of output: 1492

app/app.go (1)

Line range hint 780-784: Verify the order of hooks in OperatorKeeper.SetHooks

Ensure that the order of hooks set in OperatorKeeper is correct, as it may affect the application's behavior. The sequence can be crucial if multiple hooks interact with the same events. Please confirm that app.DistrKeeper.OperatorHooks() should be set before app.StakingKeeper.OperatorHooks().

🧰 Tools
🪛 GitHub Check: build

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

🪛 GitHub Check: test-unit-cover

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

🪛 GitHub Check: Run golangci-lint

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

x/feedistribution/keeper/impl_epoch_hooks.go (1)

42-42: Ensure all calls to AllocateTokens are updated

The AllocateTokens function is now called with a boolean parameter false to indicate that it is not triggered by a slashing event. Please verify that this change aligns with the updated function signature and logic.

x/feedistribution/keeper/impl_operator_hooks.go (1)

43-54: Implementation of AfterSlash hook

The AfterSlash method logs the event and calls AllocateTokens(ctx, true) to allocate tokens after a slashing event. The error handling is appropriate. Ensure that this implementation aligns with the intended business logic for handling slashing events.

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

59-65: Addition of MintKeeper and AVSKeeper interfaces

The new interfaces MintKeeper and AVSKeeper are appropriately defined to extend the expected keepers' functionality. This aligns with the practice of extending interfaces without causing conflicts, as per previous learnings.

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

Line range hint 27-68: Verify slash event handling implementation.

While these changes add the necessary dependencies for handling slash events, the actual implementation of slash event handling is not visible in this file. Let's verify the implementation exists in related files.

✅ Verification successful

Slash event handling is implemented through fee allocation mechanism

The verification reveals that slash event handling is properly implemented in the fee distribution module through the following mechanisms:

  1. The AllocateTokens function in allocation.go explicitly handles slash events through its isSlash parameter
  2. The module integrates with the epoch system for regular distribution, while also supporting slash-triggered distributions
  3. The implementation correctly manages both collected fees and minted coins during slash events

The changes in the keeper's dependencies are necessary to support this implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for slash event handling implementation

# Search for slash event handling
echo "Checking for slash event handling..."
rg -l "slash|Slash" --type go

# Search for specific hook implementations
echo "Checking for hook implementations..."
ast-grep --pattern 'func $FUNC($CTX, $ADDR) {
  $$$
}'

Length of output: 11531


Script:

#!/bin/bash
# Let's check the implementation of slash event handling in feedistribution module

# Check for slash-related hooks in feedistribution
echo "Checking feedistribution hooks..."
rg -A 10 "AfterValidatorSlashed|BeforeValidatorSlashed" x/feedistribution/

# Check for slash event handling in operator hooks implementation
echo "Checking operator hooks implementation..."
rg -A 10 "AfterValidatorSlashed" x/feedistribution/keeper/impl_operator_hooks.go

# Look for any slash-related functions in allocation
echo "Checking allocation handling..."
rg -A 10 "slash|Slash" x/feedistribution/keeper/allocation.go

Length of output: 1883


Script:

#!/bin/bash
# Let's check the epoch hooks implementation since slash events seem to be handled through epochs

# Check epoch hooks implementation
echo "Checking epoch hooks implementation..."
rg -A 10 "AfterEpochEnd|BeforeEpochStart" x/feedistribution/keeper/impl_epoch_hooks.go

# Check for any slash-related state management
echo "Checking for slash state management..."
fd -e go . x/feedistribution/keeper/ -x rg -l "slash|Slash"

# Look for any tests related to slash handling
echo "Checking for slash-related tests..."
fd -e go . x/feedistribution/ -x rg -l "TestSlash|test.*Slash"

Length of output: 1845

} else {
passedDuration := sdkmath.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
epochDuration := sdkmath.LegacyNewDec(int64(epochInfo.Duration))
mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using mutable operations on decimals

Using MulMut modifies the decimal value in place, which can lead to unintended side effects. It's safer to use immutable methods like Mul, which returns a new decimal. Please replace MulMut with Mul.

Apply this diff to use immutable decimal operations:

- mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
+ mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
📝 Committable suggestion

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

Suggested change
mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))

Comment on lines 44 to 48
passedDuration := sdkmath.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
epochDuration := sdkmath.LegacyNewDec(int64(epochInfo.Duration))
mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the calculation of passedDuration and epochDuration

Currently, passedDuration and epochDuration are calculated by converting a time.Duration to int64, which represents the duration in nanoseconds. This may lead to incorrect calculations, as the minting logic likely expects durations in seconds. Please update the calculation to use the correct time units.

Apply this diff to correct the duration calculations:

- passedDuration := sdkmath.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
- epochDuration := sdkmath.LegacyNewDec(int64(epochInfo.Duration))
+ passedDuration := sdkmath.LegacyNewDec(ctx.BlockTime().Sub(epochInfo.StartTime).Seconds())
+ epochDuration := sdkmath.LegacyNewDec(epochInfo.Duration.Seconds())
📝 Committable suggestion

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

Suggested change
passedDuration := sdkmath.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
epochDuration := sdkmath.LegacyNewDec(int64(epochInfo.Duration))
mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
}
passedDuration := sdkmath.LegacyNewDec(ctx.BlockTime().Sub(epochInfo.StartTime).Seconds())
epochDuration := sdkmath.LegacyNewDec(epochInfo.Duration.Seconds())
mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
}

⚠️ Potential issue

Handle potential division by zero in epoch duration calculation

If epochDuration is zero, passedDuration.QuoTruncate(epochDuration) will result in a division by zero error, causing a panic. Please ensure that epochDuration is not zero before performing the division, and handle the potential error appropriately.

Apply this diff to add a check for zero epochDuration:

+ if epochDuration.IsZero() {
+     logger.Error("Epoch duration is zero, cannot calculate minted coin portion")
+     feesCollected = feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
+ } else {
      mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
      feesCollected = feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
+ }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +27 to +28
mintKeeper types.MintKeeper
avsKeeper types.AVSKeeper
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Interface mismatch detected in AVSKeeper implementations

The verification reveals inconsistencies in AVSKeeper interface definitions across modules:

  • x/feedistribution/types: Only defines IsAVSByChainID(ctx, chainID) (bool, string)
  • x/appchain/coordinator/types: Has different return type for IsAVSByChainID - (bool, common.Address)
  • x/dogfood/types: Has additional methods and matches feedistribution's return type
  • x/operator/types: Has completely different method set

This needs to be addressed to ensure type safety and consistent behavior across modules.

🔗 Analysis chain

LGTM! Verify interface implementations.

The new keeper dependencies are properly declared. To ensure correctness, let's verify the interface implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify interface implementations for MintKeeper and AVSKeeper

# Check for MintKeeper interface definition and implementations
echo "Checking MintKeeper interface and implementations..."
rg -A 5 "type MintKeeper interface" 

# Check for AVSKeeper interface definition and implementations
echo "Checking AVSKeeper interface and implementations..."
rg -A 5 "type AVSKeeper interface"

Length of output: 2747

Comment on lines +67 to +68
mintKeeper: mintKeeper,
avsKeeper: avsKeeper,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for new keepers.

Consider adding nil checks for mintKeeper and avsKeeper similar to the accountKeeper validation above. This follows Cosmos SDK best practices and prevents potential runtime panics.

 func NewKeeper(...) Keeper {
     // ensure distribution module account is set
     if addr := accountKeeper.GetModuleAddress(types.ModuleName); addr == nil {
         panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
     }

+    // ensure mint keeper is set
+    if mintKeeper == nil {
+        panic("mint keeper is nil")
+    }
+
+    // ensure avs keeper is set
+    if avsKeeper == nil {
+        panic("avs keeper is nil")
+    }

     if _, err := sdk.AccAddressFromBech32(authority); err != nil {
         panic(fmt.Sprintf("invalid authority address: %s", authority))
     }
📝 Committable suggestion

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

Suggested change
mintKeeper: mintKeeper,
avsKeeper: avsKeeper,
mintKeeper: mintKeeper,
avsKeeper: avsKeeper,
// ensure mint keeper is set
if mintKeeper == nil {
panic("mint keeper is nil")
}
// ensure avs keeper is set
if avsKeeper == nil {
panic("avs keeper is nil")
}

@leonz789 leonz789 force-pushed the develop-distribution-stakers branch from 21bab9d to ec92007 Compare December 8, 2024 04:54
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 (1)
x/feedistribution/keeper/allocation.go (1)

154-154: Fix grammatical error in log message

The error message contains a grammatical error: "Skipping distribution for due to fail to generate avsAddr from chainID". Please revise it for clarity.

Consider changing it to:

- logger.Error("Skipping distribution for due to fail to generate avsAddr from chainID", "chainID", ctx.ChainID())
+ logger.Error("Skipping distribution due to failure to generate avsAddr from chainID", "chainID", ctx.ChainID())
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 21bab9d and ec92007.

📒 Files selected for processing (6)
  • app/app.go (1 hunks)
  • x/feedistribution/keeper/allocation.go (2 hunks)
  • x/feedistribution/keeper/impl_epoch_hooks.go (1 hunks)
  • x/feedistribution/keeper/impl_operator_hooks.go (1 hunks)
  • x/feedistribution/keeper/keeper.go (3 hunks)
  • x/feedistribution/types/expected_keepers.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • x/feedistribution/types/expected_keepers.go
  • x/feedistribution/keeper/impl_epoch_hooks.go
  • x/feedistribution/keeper/keeper.go
  • x/feedistribution/keeper/impl_operator_hooks.go
🔇 Additional comments (4)
app/app.go (1)

780-782: Verify compatibility of added operator hook

The addition of app.DistrKeeper.OperatorHooks() to OperatorKeeper.SetHooks() introduces a new interaction between the Operator module and the Distribution module. Please verify that OperatorKeeper is designed to handle hooks from DistrKeeper and that this integration does not introduce unintended side effects or cyclic dependencies.

🧰 Tools
🪛 GitHub Check: test-unit-cover

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

🪛 GitHub Check: build

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

🪛 GitHub Check: Run golangci-lint

[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks


[failure] 781-781:
too many arguments in call to (&app.OperatorKeeper).SetHooks

x/feedistribution/keeper/allocation.go (3)

44-45: ⚠️ Potential issue

[Duplicate Comment] Correct the calculation units of passedDuration and epochDuration

Currently, passedDuration and epochDuration are calculated by converting a time.Duration to int64, which represents nanoseconds. This may lead to incorrect calculations due to unit mismatch. Consider using the .Seconds() method to obtain the duration in seconds for accurate calculations.

Apply this diff to correct the duration calculations:

- passedDuration := sdkmath.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
- epochDuration := sdkmath.LegacyNewDec(int64(epochInfo.Duration))
+ passedDuration := sdkmath.LegacyNewDec(ctx.BlockTime().Sub(epochInfo.StartTime).Seconds())
+ epochDuration := sdkmath.LegacyNewDec(epochInfo.Duration.Seconds())

46-46: 🛠️ Refactor suggestion

[Duplicate Comment] Avoid mutable operations on decimals

Using MulMut modifies the decimal value in place, which can lead to unintended side effects. It's safer to use immutable methods like Mul, which returns a new decimal value. Please replace MulMut with Mul.

Apply this diff to use immutable decimal operations:

- mintedCoinDec.Amount.MulMut(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
+ mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))

45-46: ⚠️ Potential issue

[Duplicate Comment] Handle potential division by zero

If epochDuration is zero, the division passedDuration.QuoTruncate(epochDuration) will result in a division by zero error, causing a panic. Please add a check to ensure epochDuration is not zero before performing the division.

Apply this diff to add a check for zero epochDuration:

+ if epochDuration.IsZero() {
+     logger.Error("Epoch duration is zero, cannot calculate minted coin portion")
+     feesCollected = feesCollected.Sub(sdk.DecCoins{mintedCoinDec})
+ } else {
      mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(sdkmath.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
+ }

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)
testutil/keeper/feedistribute.go (2)

62-63: Consider adding test setup for distribution triggers.

While the keeper initialization is correct, consider adding test setup for:

  1. Slash event handling
  2. Epoch-end distribution
  3. Asset calculation based on dogfood

This will ensure the new functionality is properly tested.

Example test setup:

// Setup slash event test
slashEvent := types.NewSlashEvent(...)
ctx = ctx.WithEventManager(sdk.NewEventManager())
k.HandleSlashEvent(ctx, slashEvent)

// Setup epoch-end test
epochInfo := epochstypes.NewGenesisEpochInfo(...)
k.OnEpochEnd(ctx, epochInfo)

Line range hint 51-70: Consider testing keeper interactions.

The new distribution trigger functionality involves interaction between multiple keepers (mint, AVS, epochs). Consider adding integration tests that verify:

  1. The flow of events between keepers
  2. The order of operations during distribution
  3. State consistency across keeper boundaries

This will help ensure the robustness of the distribution trigger implementation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ec92007 and 2277e6e.

📒 Files selected for processing (9)
  • app/app.go (2 hunks)
  • proto/exocore/delegation/v1/query.proto (1 hunks)
  • testutil/keeper/feedistribute.go (4 hunks)
  • x/feedistribution/testutil/expected_account_mock.go (1 hunks)
  • x/feedistribution/testutil/expected_avs_mock.go (1 hunks)
  • x/feedistribution/testutil/expected_bank_mock.go (1 hunks)
  • x/feedistribution/testutil/expected_epochs_mock.go (1 hunks)
  • x/feedistribution/testutil/expected_mint_mock.go (1 hunks)
  • x/feedistribution/testutil/mock_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (7)
  • x/feedistribution/testutil/mock_test.go
  • proto/exocore/delegation/v1/query.proto
  • x/feedistribution/testutil/expected_epochs_mock.go
  • x/feedistribution/testutil/expected_mint_mock.go
  • x/feedistribution/testutil/expected_avs_mock.go
  • x/feedistribution/testutil/expected_account_mock.go
  • x/feedistribution/testutil/expected_bank_mock.go
🔇 Additional comments (4)
testutil/keeper/feedistribute.go (2)

11-11: LGTM! Good practice using local test utilities.

The switch to local test utilities provides better control over test implementations specific to the project's needs.


47-48: Verify mock implementations for new keepers.

The mock keepers are correctly initialized, but let's verify they implement all required methods for testing the distribution trigger functionality.

✅ Verification successful

Let me gather more information about the mock implementations.


Mock implementations are complete and correctly implemented

The mock keepers implement all required methods from their respective interfaces:

  • MockMintKeeper implements GetParams(ctx sdk.Context) minttypes.Params
  • MockAVSKeeper implements IsAVSByChainID(ctx sdk.Context, chainID string) (bool, string)

These match exactly with the interface definitions in x/feedistribution/types/expected_keepers.go, making the mocks suitable for testing the distribution trigger functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that mock implementations include all required methods

# Check the interface definitions and mock implementations
rg -A 5 "type (Mint|AVS)Keeper interface" 
ast-grep --pattern 'type Mock$_Keeper struct {
  $$$
}'

Length of output: 2367


Script:

#!/bin/bash
# Check mock implementations in the test utilities
rg -A 10 "func NewMock(Mint|AVS)Keeper" 
rg "func \(m \*Mock(Mint|AVS)Keeper\)" 

Length of output: 2293

app/app.go (2)

715-716: LGTM: DistrKeeper initialization with required dependencies

The initialization of DistrKeeper with ExomintKeeper and AVSManagerKeeper is correctly implemented to support fee distribution based on validator set changes.


782-785: Verify hook execution order for operator events

The setup of operator hooks with DistrKeeper and StakingKeeper looks correct. However, let's verify the hook execution order to ensure proper handling of slash events.

✅ Verification successful

Let me try a different approach to find the hook implementations.


Let me search for the operator hooks interface and its implementations.


Based on the findings, I can now generate the final response.

Hook execution order is correctly implemented

The MultiOperatorHooks implementation in x/operator/types/hooks.go ensures sequential execution of hooks in the order they are provided. The current setup with DistrKeeper followed by StakingKeeper hooks is appropriate as:

  • DistrKeeper's hooks (implemented in feedistribution) handle fee distribution updates
  • Both implementations are lightweight and don't interfere with each other's functionality
  • The order matches the dependency flow where distribution updates should precede staking changes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the hook execution order for operator events
# Test: Search for hook implementations to confirm execution order

# Check DistrKeeper operator hooks implementation
echo "Checking DistrKeeper operator hooks..."
ast-grep --pattern 'func ($x *Keeper) OperatorHooks() $type {
  $$$
}'

# Check StakingKeeper operator hooks implementation
echo "Checking StakingKeeper operator hooks..."
ast-grep --pattern 'func ($x *Keeper) OperatorHooks() $type {
  $$$
}'

Length of output: 323


Script:

#!/bin/bash
# Search for operator hooks in distribution and staking modules
echo "Searching for operator hooks in distribution module..."
rg -A 5 "OperatorHooks" x/distribution/

echo "Searching for operator hooks in staking module..."
rg -A 5 "OperatorHooks" x/staking/

# Search for MultiOperatorHooks implementation
echo "Searching for MultiOperatorHooks implementation..."
rg -A 10 "type MultiOperatorHooks" 

Length of output: 1116


Script:

#!/bin/bash
# Search for OperatorHooks interface definition
echo "Searching for OperatorHooks interface..."
rg -A 10 "type OperatorHooks interface" 

# Search for implementations in keeper files
echo "Searching for keeper implementations..."
fd -e go keeper.go -x rg -A 5 "OperatorHooks()" {} \;

# Search for specific hook methods to understand the execution flow
echo "Searching for hook method implementations..."
rg -A 5 "AfterOperatorKeySet|AfterOperatorBonded|AfterOperatorUnbonded" 

Length of output: 5084

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2277e6e and 5bed137.

📒 Files selected for processing (4)
  • tests/e2e/oracle/create_price.go (1 hunks)
  • testutil/network/genesis_data.go (3 hunks)
  • testutil/network/util.go (2 hunks)
  • x/feedistribution/keeper/allocation.go (5 hunks)
🔇 Additional comments (5)
testutil/network/genesis_data.go (1)

88-88: Verify the impact of reduced jail duration.

The OracleMissJailDuration has been reduced from 30s to 10s. This shorter duration might not provide sufficient time for validators to recover from temporary network issues.

x/feedistribution/keeper/allocation.go (2)

49-50: ⚠️ Potential issue

Avoid mutable decimal operations.

Using MulMut modifies the decimal value in place, which can lead to unintended side effects.

Apply this diff to use immutable operations:

-mintedCoinDec.Amount.MulMut(math.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))
+mintedCoinDec.Amount = mintedCoinDec.Amount.Mul(math.LegacyOneDec().Sub(passedDuration.QuoTruncate(epochDuration)))

Likely invalid or redundant comment.


47-49: ⚠️ Potential issue

Fix potential precision loss in duration calculations.

The conversion of time.Duration to int64 could lead to precision loss and incorrect calculations:

  1. Duration is converted to nanoseconds which might overflow int64
  2. The decimal conversion might not preserve the intended precision

Apply this diff to fix the precision issues:

-passedDuration := math.LegacyNewDec(int64(ctx.BlockTime().Sub(epochInfo.StartTime)))
-epochDuration := math.LegacyNewDec(int64(epochInfo.Duration))
+passedDuration := math.LegacyNewDec(ctx.BlockTime().Sub(epochInfo.StartTime).Seconds())
+epochDuration := math.LegacyNewDec(epochInfo.Duration.Seconds())

Likely invalid or redundant comment.

testutil/network/util.go (2)

24-24: LGTM!

The import statement follows the project's conventions and is properly grouped with other module imports.


250-252: Consider adding error handling and verify DefaultGenStateExoMint

While the initialization follows the pattern used for other modules, consider:

  1. Adding error handling similar to other module initializations
  2. Verifying that DefaultGenStateExoMint contains appropriate configuration for fee distribution triggers (slash events and epoch end)

Consider adding error handling similar to other module initializations:

 // set exomint genesis state
-cfg.GenesisState[exominttypes.ModuleName] = cfg.Codec.MustMarshalJSON(&DefaultGenStateExoMint)
+exomintGenState, err := NewGenStateExoMint()
+if err != nil {
+    return err
+}
+cfg.GenesisState[exominttypes.ModuleName] = cfg.Codec.MustMarshalJSON(&exomintGenState)

DefaultGenStateOracle.Params.Slashing.OracleMissJailDuration = 30 * time.Second
DefaultGenStateOracle.Params.Slashing.OracleMissJailDuration = 10 * time.Second
// set mint duration to minute
DefaultGenStateExoMint.Params.EpochIdentifier = epochtypes.MinuteEpochID
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistency found in epoch identifier configuration

The verification reveals an inconsistency between the test utility's epoch identifier and the actual module configuration. The DefaultGenStateExoMint in test utilities uses MinuteEpochID, while the exomint module's default configuration in x/exomint/types/params.go uses DefaultEpochIdentifier = epochstypes.DayEpochID. This mismatch could lead to unexpected behavior in tests.

  • testutil/network/genesis_data.go: Uses MinuteEpochID
  • x/exomint/types/params.go: Uses DayEpochID as default
🔗 Analysis chain

Verify epoch identifier consistency.

Ensure that the MinuteEpochID is consistently used across the codebase for minting operations.


Let me gather more specific information about epoch identifiers in the minting context.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check epoch identifier usage

# Search for MinuteEpochID references
rg "MinuteEpochID"

# Search for other epoch identifiers in minting context
ast-grep --pattern 'EpochIdentifier = $_'

Length of output: 1137


Script:

#!/bin/bash
# Search for epoch identifier configurations in minting and fee distribution contexts
rg -A 2 "EpochIdentifier.*=.*" x/feedistribution/
rg -A 2 "EpochIdentifier.*=.*" x/exomint/

# Check for any other epoch-related configurations in minting
rg -i "epoch" x/exomint/

Length of output: 14763

Comment on lines +156 to +161
chainIDWithoutRevision := avstypes.ChainIDWithoutRevision(ctx.ChainID())
isAVS, avsAddress := k.avsKeeper.IsAVSByChainID(ctx, chainIDWithoutRevision)
if !isAVS {
logger.Error("Skipping distribution for due to fail to generate avsAddr from chainID", "chainID", ctx.ChainID())
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in AVS status check.

The AVS status check returns early with just an error log. This could lead to silent failures in fee distribution.

Apply this diff to improve error handling:

 if !isAVS {
-    logger.Error("Skipping distribution for due to fail to generate avsAddr from chainID", "chainID", ctx.ChainID())
-    return
+    err := fmt.Errorf("failed to generate AVS address from chainID %s", ctx.ChainID())
+    logger.Error(err.Error())
+    return err
 }

Committable suggestion skipped: line range outside the PR's diff.

@@ -323,15 +323,14 @@ func (s *E2ETestSuite) testSlashing() {
s.Require().NoError(err)
s.Require().True(resOperator.Jailed)
// wait for validator3 to pass jail duration
time.Sleep(35 * time.Second)
time.Sleep(12 * time.Second)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider potential test flakiness.

The sleep duration has been reduced to 12s to match the new jail duration. However, this tight timing might make tests flaky, especially in CI environments with varying performance characteristics.

Consider these alternatives:

  1. Use a multiplier of the jail duration instead of hardcoded seconds
  2. Add retry logic with appropriate timeout
  3. Wait for a specific chain state instead of using sleep

Example implementation:

-time.Sleep(12 * time.Second)
+jailDuration := s.network.QueryOracle().Params(context.Background(), &oracletypes.QueryParamsRequest{}).Params.Slashing.OracleMissJailDuration
+time.Sleep(jailDuration + 2*time.Second) // Add buffer for chain processing

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant