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

feat: reduce gas for first vote by validators #2163

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

Conversation

matthiasmatt
Copy link
Contributor

@matthiasmatt matthiasmatt commented Jan 12, 2025

Purpose / Abstract


This pull request includes several changes to the Nibiru application, focusing on adding a new fee discount mechanism for validators who vote in the current period, updating the AnteHandler options, and enhancing test utilities. The most important changes include the addition of the VoteFeeDiscountDecorator, updates to the AnteHandlerOptions struct, and the implementation of new test utilities.

Fee Discount Mechanism:

  • Added VoteFeeDiscountDecorator to apply a fee discount for validators who vote in the current period (x/oracle/ante/fee_discount.go).
  • Created tests for VoteFeeDiscountDecorator to ensure correct functionality (x/oracle/ante/fee_discount_test.go).
  • Added interfaces for StakingKeeper and OracleKeeper to be used in the VoteFeeDiscountDecorator (x/oracle/ante/keeper_interface.go).

AnteHandler Options:

  • Updated AnteHandlerOptions struct to include OracleKeeper and StakingKeeper (app/ante/handler_opts.go).
  • Modified NewAnteHandlerNonEVM to include the new VoteFeeDiscountDecorator (app/ante.go).

Test Utilities:

  • Added AddTestAddrsIncremental function to generate test addresses and optionally fund them (x/common/testutil/testapp/testapp.go).

Additional Changes:

  • Added imports for oracleante and stakingkeeper in relevant files (app/ante.go, app/ante/handler_opts.go). [1] [2]
  • Updated NewNibiruApp to include OracleKeeper and StakingKeeper in the options (app/app.go).

These changes enhance the functionality and testability of the Nibiru application by introducing a new fee discount mechanism for validators and improving the configuration and testing capabilities of the application.

Summary by CodeRabbit

Based on the comprehensive changes, here are the release notes:

Release Notes

  • New Features

    • Introduced a gas fee discount mechanism for validators' first vote in the oracle module
    • Added utility function for generating test addresses incrementally
  • Improvements

    • Enhanced ante handler configuration with additional keeper dependencies
    • Expanded testing capabilities for oracle module's vote fee discount
  • Technical Updates

    • Updated changelog to reflect new gas reduction feature
    • Added new interfaces and decorators to support oracle voting functionality

The release focuses on optimizing validator interactions and improving the testing infrastructure for the Nibiru EVM project.

@matthiasmatt matthiasmatt requested a review from a team as a code owner January 12, 2025 14:00
Copy link
Contributor

coderabbitai bot commented Jan 12, 2025

Walkthrough

This pull request introduces a new feature to reduce gas costs for validators' first votes in the Nibiru EVM project. The changes span multiple files, including the changelog, ante handler, and oracle module. A new VoteFeeDiscountDecorator is implemented to provide gas fee discounts for validators voting for the first time in a period, specifically targeting oracle-related transactions. The modifications aim to make oracle voting more cost-efficient for validators while maintaining transaction integrity.

Changes

File Change Summary
CHANGELOG.md Added entry for feature reducing gas for first validator vote
app/ante.go Added import and decorator for oracle vote fee discount
app/ante/handler_opts.go Added OracleKeeper and StakingKeeper fields to AnteHandlerOptions
app/app.go Updated NewNibiruApp to include new keeper parameters
x/common/testutil/testapp/testapp.go Added AddTestAddrsIncremental utility function
x/oracle/ante/fee_discount.go New file implementing VoteFeeDiscountDecorator
x/oracle/ante/fee_discount_test.go Added comprehensive test suite for fee discount decorator
x/oracle/ante/keeper_interface.go Defined interfaces for staking and oracle keepers
x/oracle/keeper/ballot.go Added HasVotedInCurrentPeriod method

Sequence Diagram

sequenceDiagram
    participant Tx as Transaction
    participant Ante as AnteHandler
    participant VoteDiscount as VoteFeeDiscountDecorator
    participant Oracle as OracleKeeper
    participant Staking as StakingKeeper

    Tx->>Ante: Submit Transaction
    Ante->>VoteDiscount: Check Transaction
    VoteDiscount->>Staking: Is Validator Valid?
    Staking-->>VoteDiscount: Validator Details
    VoteDiscount->>Oracle: Has Voted in Current Period?
    Oracle-->>VoteDiscount: Voting Status
    alt First Vote
        VoteDiscount->>Ante: Reduce Gas Fees
    else Already Voted
        VoteDiscount->>Ante: Standard Gas Fees
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
Reduce oracle gas costs
Check for single message transaction
Validate eligible oracle voter
Prevent spam Requires further monitoring of implementation

Possibly related PRs

Poem

🐰 Hop, hop, through the blockchain's maze,
Validators' votes now dance with grace,
Gas fees tumble, light as a feather,
Oracle's whispers, bound together!
CodeRabbit's magic makes transactions fair! 🌟

Finishing Touches

  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

@matthiasmatt matthiasmatt requested a review from Copilot January 12, 2025 14:02

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 9 changed files in this pull request and generated no comments.

Files not reviewed (4)
  • app/ante/handler_opts.go: Evaluated as low risk
  • app/app.go: Evaluated as low risk
  • CHANGELOG.md: Evaluated as low risk
  • x/oracle/keeper/ballot.go: Evaluated as low risk
Comments suppressed due to low confidence (2)

x/oracle/ante/fee_discount.go:36

  • [nitpick] The variable name 'vfd' is ambiguous. It should be renamed to 'voteFeeDiscountDecorator' for better readability.
vfd VoteFeeDiscountDecorator

x/oracle/ante/fee_discount.go:46

  • The error message should be more descriptive. Suggest changing to 'invalid transaction type for VoteFeeDiscountDecorator: %T'.
return ctx, sdkerrors.Wrapf(sdkerrors.ErrTxDecode, "invalid tx type %T", tx)
Copy link

codecov bot commented Jan 12, 2025

Codecov Report

Attention: Patch coverage is 94.73684% with 3 lines in your changes missing coverage. Please review.

Project coverage is 65.22%. Comparing base (f3ca671) to head (001cc0a).

Files with missing lines Patch % Lines
x/oracle/ante/fee_discount.go 93.87% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2163      +/-   ##
==========================================
+ Coverage   65.14%   65.22%   +0.07%     
==========================================
  Files         277      278       +1     
  Lines       22238    22292      +54     
==========================================
+ Hits        14488    14539      +51     
- Misses       6760     6762       +2     
- Partials      990      991       +1     
Files with missing lines Coverage Δ
app/ante.go 76.66% <100.00%> (+0.39%) ⬆️
app/ante/handler_opts.go 0.00% <ø> (ø)
app/app.go 57.36% <100.00%> (+0.21%) ⬆️
x/oracle/keeper/ballot.go 90.29% <100.00%> (+0.29%) ⬆️
x/oracle/ante/fee_discount.go 93.87% <93.87%> (ø)

@Unique-Divine
Copy link
Member

This is great. We've had this ticket open a while

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 comments (1)
app/ante/handler_opts.go (1)

Line range hint 55-57: Validate New Keepers in AnteHandlerOptions

The ValidateAndClean method should include checks to ensure that OracleKeeper and StakingKeeper are not nil, similar to the other keepers. This prevents potential nil pointer dereferences during AnteHandler execution.

Apply this diff to add validation:

	func (opts *AnteHandlerOptions) ValidateAndClean() error {
		if opts.BankKeeper == nil {
			return AnteHandlerError("bank keeper")
		}
+		if opts.OracleKeeper == nil {
+			return AnteHandlerError("oracle keeper")
+		}
+		if opts.StakingKeeper == nil {
+			return AnteHandlerError("staking keeper")
+		}
🧹 Nitpick comments (9)
x/oracle/ante/fee_discount.go (4)

19-22: Consider Interface Naming Conventions for Clarity

The interfaces OracleKeeperI and StakingKeeperI could be renamed to OracleKeeper and StakingKeeper respectively, removing the trailing I. This aligns with Go naming conventions, where interface names are typically not suffixed unless necessary for disambiguation.


37-42: Simplify AnteDecorator Logic for Multiple Signers

Currently, the decorator checks for exactly one signer and passes through if there are multiple signers (lines 54-57). If the discount is intended only for single-signer transactions, consider explicitly handling multi-signer transactions by returning an error or documenting the intended behavior for clarity.


59-66: Extend Message Type Checks to Support Future Oracle Messages

The current implementation only allows MsgAggregateExchangeRatePrevote and MsgAggregateExchangeRateVote. To enhance flexibility, consider supporting additional oracle-related message types or refactoring the check to accommodate future message expansions.


13-18: Remove Residual Comments from Template Code

The comments in lines 13-18 suggest that this code may be adapted from a template or example. For production code, remove or update these comments to reflect the actual logic and context of the application to avoid confusion.

x/oracle/ante/keeper_interface.go (1)

16-18: Document Interface Purpose and Usage

Add comments to the OracleKeeperI interface to clarify its role and how it should be implemented. This will aid in maintenance and ensure consistent implementation across different modules.

app/ante/handler_opts.go (2)

13-14: Optimize Imports for Consistency

The imports for stakingkeeper and oraclekeeper could be grouped with related imports for clarity and to adhere to Go import grouping conventions (standard library, third-party, local packages).


29-31: Use Interfaces Instead of Concrete Types in AnteHandlerOptions

In the AnteHandlerOptions struct, consider using interfaces (StakingKeeperI and OracleKeeperI) instead of concrete keeper types. This promotes abstraction and makes the codebase more modular and testable.

Apply this diff to use interfaces:

-	OracleKeeper  oraclekeeper.Keeper
-	StakingKeeper stakingkeeper.Keeper
+	OracleKeeper  ante.OracleKeeperI
+	StakingKeeper ante.StakingKeeperI
x/oracle/keeper/ballot.go (1)

104-107: Add documentation and improve error handling.

The method implementation is correct but could benefit from:

  1. Documentation explaining the return value (true if voted, false otherwise).
  2. Explicit error type checking instead of using a generic error check.

Apply this diff to improve the implementation:

+// HasVotedInCurrentPeriod returns true if the validator has already voted in the
+// current voting period, false otherwise.
 func (k Keeper) HasVotedInCurrentPeriod(ctx sdk.Context, valAddr sdk.ValAddress) bool {
-    _, err := k.Votes.Get(ctx, valAddr)
-    return err == nil
+    _, err := k.Votes.Get(ctx, valAddr)
+    return !collections.IsNotFound(err)
 }
x/oracle/ante/fee_discount_test.go (1)

62-111: Consider adding validation for empty signers array.

The buildTestTx helper function is well-implemented but should validate that the signers array is not empty to prevent potential panics.

Add this validation at the start of the function:

 func (s *VoteFeeDiscountTestSuite) buildTestTx(msgs []sdk.Msg, signers []sdk.AccAddress) (sdk.Tx, error) {
+    if len(signers) == 0 {
+        return nil, fmt.Errorf("at least one signer is required")
+    }
     // Rest of the implementation...
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3ca671 and 001cc0a.

📒 Files selected for processing (9)
  • CHANGELOG.md (1 hunks)
  • app/ante.go (2 hunks)
  • app/ante/handler_opts.go (2 hunks)
  • app/app.go (2 hunks)
  • x/common/testutil/testapp/testapp.go (2 hunks)
  • x/oracle/ante/fee_discount.go (1 hunks)
  • x/oracle/ante/fee_discount_test.go (1 hunks)
  • x/oracle/ante/keeper_interface.go (1 hunks)
  • x/oracle/keeper/ballot.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: integration-tests
🔇 Additional comments (8)
x/oracle/ante/keeper_interface.go (1)

10-13: Align Interface Methods with Required Functionality

Verify that the StakingKeeperI interface includes all necessary methods required by the VoteFeeDiscountDecorator. If future methods are needed, consider embedding stakingtypes.StakingKeeper or selectively adding methods to minimize interface exposure.

app/ante.go (1)

76-76: LGTM! Appropriate placement of the VoteFeeDiscountDecorator.

The decorator is correctly positioned in the ante handler chain:

  • After basic validation (ValidateBasic)
  • Before fee deduction
  • Before memo validation and timeout checks
x/common/testutil/testapp/testapp.go (1)

160-195: LGTM! Well-structured test utility function.

The implementation is clean and well-documented with:

  • Clear step-by-step process
  • Appropriate error handling
  • Proper key generation using secp256k1
  • Optional funding capability
x/oracle/ante/fee_discount_test.go (2)

23-44: LGTM! Clean mock implementations.

The mock implementations for StakingKeeper and OracleKeeper are minimal yet sufficient for testing purposes.


138-342: LGTM! Comprehensive test coverage.

The test scenarios are thorough and cover:

  • Happy path
  • Invalid transaction types
  • Multiple signers
  • Non-oracle messages
  • Validator conditions (not found, jailed, threshold)
  • Already voted case
app/app.go (2)

219-221: LGTM! Code formatting improvement.

The reformatting of keeper assignments improves code readability.


232-233: LGTM! Required keepers for vote fee discount feature.

The addition of StakingKeeper and OracleKeeper to the ante handler options is necessary for implementing the validator vote fee discount feature.

CHANGELOG.md (1)

265-265: LGTM! Clear and concise changelog entry.

The changelog entry correctly documents the feature addition and is placed in the appropriate section since it modifies state machine behavior around gas fees.

Comment on lines +87 to +98
// 3. If validator, we check whether they've posted a vote this period
hasVoted := vfd.oracleKeeper.HasVotedInCurrentPeriod(ctx, valAddr)
if !hasVoted {
// 4. If first time, let's say we reduce gas cost.
minGasPrices := ctx.MinGasPrices()
var discounted []sdk.DecCoin
for _, mgp := range minGasPrices {
discounted = append(discounted, sdk.NewDecCoinFromDec(mgp.Denom, mgp.Amount.QuoInt64(69_420)))
}
// We'll create a new context with the updated MinGasPrices
ctx = ctx.WithMinGasPrices(discounted)
}
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

Ensure Gas Discount Logic Correctly Applies Discounts

The gas price reduction divides the MinGasPrices by 69,420 (line 94), which seems arbitrary and may reduce fees below acceptable limits, potentially affecting network security.

Consider revising the discount factor to a more appropriate value or making it configurable.

Apply this diff to adjust the discount factor:

-			discounted = append(discounted, sdk.NewDecCoinFromDec(mgp.Denom, mgp.Amount.QuoInt64(69_420)))
+			discountFactor := sdk.NewDecWithPrec(5, 1) // 50% discount
+			discountedAmount := mgp.Amount.Mul(discountFactor)
+			discounted = append(discounted, sdk.NewDecCoinFromDec(mgp.Denom, discountedAmount))

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

Comment on lines +79 to +85
// needs to have at least 0.5% of the supply bonded
totalBonded := vfd.stakingKeeper.TotalBondedTokens(ctx)
currentlyBonded := validator.Tokens

if currentlyBonded.LT(totalBonded.Mul(math.NewInt(50)).Quo(math.NewInt(10000))) {
return next(ctx, tx, simulate)
}
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

Adjust Bonded Tokens Threshold Calculation for Precision

The calculation for determining if a validator has at least 0.5% of the bonded tokens (line 83) uses integer arithmetic, which may lead to imprecise results due to truncation. Consider using precise decimal arithmetic with sdk.Dec to ensure accuracy in the threshold calculation.

Apply this diff to enhance precision:

-	if currentlyBonded.LT(totalBonded.Mul(math.NewInt(50)).Quo(math.NewInt(10000))) {
+	threshold := sdk.NewDecFromInt(totalBonded).Mul(sdk.NewDecWithPrec(5, 3)) // 0.5%
+	if sdk.NewDecFromInt(currentlyBonded).LT(threshold) {
📝 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
// needs to have at least 0.5% of the supply bonded
totalBonded := vfd.stakingKeeper.TotalBondedTokens(ctx)
currentlyBonded := validator.Tokens
if currentlyBonded.LT(totalBonded.Mul(math.NewInt(50)).Quo(math.NewInt(10000))) {
return next(ctx, tx, simulate)
}
// needs to have at least 0.5% of the supply bonded
totalBonded := vfd.stakingKeeper.TotalBondedTokens(ctx)
currentlyBonded := validator.Tokens
threshold := sdk.NewDecFromInt(totalBonded).Mul(sdk.NewDecWithPrec(5, 3)) // 0.5%
if sdk.NewDecFromInt(currentlyBonded).LT(threshold) {
return next(ctx, tx, simulate)
}

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

Successfully merging this pull request may close these issues.

feat(oracle): oracle gas needs to be low/negligible
2 participants