Skip to content

Conversation

meetrick
Copy link
Contributor

@meetrick meetrick commented Aug 26, 2025

Description

Closes: #25169

Problem

Transactions fail with unclear error messages when users set timeout_height to current block height, causing repeated failures and poor UX.

Solution

  • Add pre-validation to check if timeout height equals current block height
  • Provide clear error messages showing expected next block height
  • Add GetRecommendedTimeoutHeight() helper function

Changes

  • x/auth/ante/basic.go: Enhanced TxTimeoutHeightDecorator validation logic
  • x/auth/ante/basic_test.go: Updated tests and added helper function tests

Benefits

  • Reduces repeated error logs
  • Improves user experience with clear guidance
  • Prevents invalid transactions early
  • Provides helper for correct timeout height calculation

Testing

  • All existing tests pass
  • New validation logic tested
  • Helper function teste

Summary by CodeRabbit

  • New Features

    • Added guidance to suggest a recommended timeout height (defaults to next block height), helping users set valid transaction timeouts.
  • Bug Fixes

    • Transactions with a timeout height equal to the current block height are now rejected to prevent immediate expiry.
    • Improved error messages when a transaction’s timeout has already passed, providing clearer instructions on how to set a valid timeout height.

Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

📝 Walkthrough

Walkthrough

Changes adjust TxTimeoutHeightDecorator to treat timeout height equal to current block height as invalid, differentiate error messages for equal vs. past timeouts, and retain timestamp checks. A new utility GetRecommendedTimeoutHeight(currentHeight, buffer) was added. Tests updated accordingly and a new test added for the helper.

Changes

Cohort / File(s) Summary
Ante timeout height validation
x/auth/ante/basic.go
Introduces GetRecommendedTimeoutHeight(currentHeight, buffer). Refactors AnteHandle logic: computes currentHeight once; if timeoutHeight == currentHeight, returns specific error suggesting next block height; if currentHeight > timeoutHeight, returns “already passed” error; timestamp checks unchanged.
Tests
x/auth/ante/basic_test.go
Updates TestTxTimeoutHeightDecorator to expect error when timeout height equals current height. Adds TestGetRecommendedTimeoutHeight covering default buffer, custom buffer, zero height, and large height cases.

Sequence Diagram(s)

sequenceDiagram
  participant Tx as Tx
  participant Ante as AnteHandler
  participant THD as TxTimeoutHeightDecorator
  participant Next as Next Ante

  Tx->>Ante: DeliverTx(CheckTx)
  Ante->>THD: AnteHandle(ctx, tx, simulate)
  THD->>THD: currentHeight = ctx.BlockHeight()
  alt timeoutHeight == 0
    THD->>Next: AnteHandle(...)
    Next-->>Ante: result/err
  else timeoutHeight != 0
    alt timeoutHeight == currentHeight
      THD-->>Ante: error("set to next block height")
    else currentHeight > timeoutHeight
      THD-->>Ante: error("timeout already passed")
    else currentHeight < timeoutHeight
      THD->>THD: check timestamp constraints
      alt timestamp invalid
        THD-->>Ante: error(timestamp)
      else timestamp ok
        THD->>Next: AnteHandle(...)
        Next-->>Ante: result/err
      end
    end
  end
  Ante-->>Tx: result/err
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Assessment against linked issues

Objective Addressed Explanation
Prevent duplicate logging of same errors (#25169) No deduplication or aggregation of repeated errors added; only error text/branches changed.
Log same errors only once per minute (#25169) No rate-limiting or time-based logging controls implemented.
Keep important issues visible (#25169) No logging changes; unclear impact on visibility without log throttling.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Add GetRecommendedTimeoutHeight helper (x/auth/ante/basic.go) Not related to deduplicating or rate-limiting logs; utility for computing suggested timeout height.
Reject timeout height equal to current block height with new error path (x/auth/ante/basic.go) Behavioral change to validation; does not implement log deduplication or throttling requested in the issue.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 0

🧹 Nitpick comments (7)
x/auth/ante/basic.go (5)

201-208: Guard against uint64 overflow and document semantics in helper.

While practically unreachable, currentHeight + buffer can overflow uint64. Add a cheap overflow guard and clarify that buffer=0 means “next block.”

Apply this diff within the helper:

 func GetRecommendedTimeoutHeight(currentHeight uint64, buffer uint64) uint64 {
   if buffer == 0 {
     buffer = 1 // Default buffer of 1 block
   }
-  return currentHeight + buffer
+  // Saturating add to guard against uint64 overflow (extremely unlikely in practice).
+  sum := currentHeight + buffer
+  if sum < currentHeight { // overflow detected
+    return ^uint64(0)
+  }
+  return sum
 }

223-233: Use the new helper and tighten the error message.

  • Use GetRecommendedTimeoutHeight for consistency and to inherit any future logic (like overflow/safety).
  • Improve grammar and clarity in the error string. “must be strictly greater than the current block height” communicates the rule directly.
   if timeoutHeight > 0 {
     // Check if timeout height is set to current block height (which is invalid)
     if timeoutHeight == currentHeight {
-      nextBlockHeight := currentHeight + 1
+      nextBlockHeight := GetRecommendedTimeoutHeight(currentHeight, 1)
       return ctx, errorsmod.Wrapf(
         sdkerrors.ErrTxTimeoutHeight,
-        "you must set the timeout height to be the next block height got %d, expected %d",
-        timeoutHeight, nextBlockHeight,
+        "timeout height must be strictly greater than the current block height: got %d, expected at least %d",
+        timeoutHeight, nextBlockHeight,
       )
     }

234-241: Offer an actionable hint when the timeout height is in the past.

Adding a recommendation in the error reduces back-and-forth for users and aligns with the PR goal of clearer guidance.

     // Check if timeout height has already passed
     if currentHeight > timeoutHeight {
       return ctx, errorsmod.Wrapf(
         sdkerrors.ErrTxTimeoutHeight,
-        "transaction timeout height %d has already passed; current block height is %d",
-        timeoutHeight, currentHeight,
+        "transaction timeout height %d has already passed; current block height is %d (try >= %d)",
+        timeoutHeight, currentHeight, GetRecommendedTimeoutHeight(currentHeight, 1),
       )
     }

210-214: Minor naming nit: comments refer to TxHeightTimeoutDecorator instead of TxTimeoutHeightDecorator.

The type is TxTimeoutHeightDecorator; the doc comments here (and above the interface) say TxHeightTimeoutDecorator. Consider aligning names to avoid confusion and lint warnings.


223-241: PR objective mismatch: duplicate error log rate-limiting isn’t addressed here.

The linked issue (#25169) requests rate-limiting identical timeout-height errors (e.g., “only once per minute”). Updating the error message helps UX but won’t reduce duplicate validator logs by itself. That requires changes where logging occurs (CheckTx/DeliverTx error handling in baseapp or logger configuration), not inside this decorator.

Recommendations:

  • Implement log sampling/dedup at the app/logger layer keyed by (height, error code, message template).
  • Alternatively, cache the last logged error per height with a TTL in the CheckTx path.

Please confirm whether the PR should still “close” #25169 or if a follow-up is planned.

x/auth/ante/basic_test.go (2)

182-237: Add assertions for the new, more actionable error messages.

The PR goal is clearer errors, but tests currently only assert on the error type. Add targeted checks for message content for:

  • equal-to-current-height case
  • past-height case

This prevents regressions and ensures the guidance (including expected next height) is preserved.

You can append a focused subtest:

func TestTxTimeoutHeightDecorator_ErrorMessages(t *testing.T) {
  suite := SetupTestSuite(t, true)
  antehandler := sdk.ChainAnteDecorators(ante.NewTxTimeoutHeightDecorator())
  priv1, _, addr1 := testdata.KeyTestPubAddr()
  msg := testdata.NewTestMsg(addr1)
  feeAmount := testdata.NewTestFeeAmount()
  gasLimit := testdata.NewTestGasLimit()

  // Build a base tx
  suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
  require.NoError(t, suite.txBuilder.SetMsgs(msg))
  suite.txBuilder.SetFeeAmount(feeAmount)
  suite.txBuilder.SetGasLimit(gasLimit)

  // Case 1: same height -> require “strictly greater/next block” guidance
  {
    suite.txBuilder.SetTimeoutHeight(10)
    suite.txBuilder.SetTimeoutTimestamp(time.Time{})
    privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
    tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
    require.NoError(t, err)

    ctx := suite.ctx.WithBlockHeight(10)
    _, err = antehandler(ctx, tx, true)
    require.ErrorIs(t, err, sdkerrors.ErrTxTimeoutHeight)
    require.ErrorContains(t, err, "next block height")
  }

  // Case 2: past height -> require hint to try >= next block
  {
    suite.txBuilder.SetTimeoutHeight(9)
    suite.txBuilder.SetTimeoutTimestamp(time.Time{})
    privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
    tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
    require.NoError(t, err)

    ctx := suite.ctx.WithBlockHeight(10)
    _, err = antehandler(ctx, tx, true)
    require.ErrorIs(t, err, sdkerrors.ErrTxTimeoutHeight)
    require.ErrorContains(t, err, "has already passed")
  }
}

239-258: Nice coverage for the helper; consider one boundary case.

Tests look good and cover the default buffer path. Optionally add an overflow boundary check (expected to saturate if you adopt the suggested overflow guard), or at least a documentation note that overflow behavior is unspecified if not guarded.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 79fcc30 and ac89cc1.

📒 Files selected for processing (2)
  • x/auth/ante/basic.go (2 hunks)
  • x/auth/ante/basic_test.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (3)
x/auth/ante/basic.go (2)

221-222: Type alignment for height comparisons looks good.

Casting ctx.BlockHeight() to uint64 aligns types and removes mixed-signedness comparisons. No concerns here.


223-241: This change is a behavioral break; please call it out and verify downstream impacts.

Previously, timeoutHeight == currentHeight was accepted (so long as DeliverTx happened at that height). Now it’s rejected. This tightens correctness but can break existing clients/wallets that set “current height” as the timeout.

  • Add a release note entry and migration note.
  • Verify common wallets/SDK clients don’t default to “equal height.”
  • Confirm no chain tooling relies on the old acceptance semantics.
x/auth/ante/basic_test.go (1)

207-208: Test expectation update looks correct.

Switching “same height” to expect sdkerrors.ErrTxTimeoutHeight reflects the new stricter validation.

- Prevent timeout height = current block height
- Add clear error messages and helper function
- Improve user experience and reduce error logs

Signed-off-by: Hwangjae Lee <[email protected]>
- Add error message validation tests
- Add overflow boundary tests
- Fix timeout height test cases

Signed-off-by: Hwangjae Lee <[email protected]>
Signed-off-by: Hwangjae Lee <[email protected]>
@meetrick meetrick force-pushed the 20250826_timeout_handler branch from 2fbcfd6 to ae791bf Compare August 27, 2025 02:56
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.

Duplicate timeout height error logs create noise in validator nodes
1 participant