Skip to content

fix: handle "tx already in cache" gracefully#1728

Merged
baktun14 merged 2 commits intoakash-network:mainfrom
jzsfkzm:bugfixes/1692-handle-tx-in-cache-gracefully
Aug 4, 2025
Merged

fix: handle "tx already in cache" gracefully#1728
baktun14 merged 2 commits intoakash-network:mainfrom
jzsfkzm:bugfixes/1692-handle-tx-in-cache-gracefully

Conversation

@jzsfkzm
Copy link
Contributor

@jzsfkzm jzsfkzm commented Jul 23, 2025

closes #1692

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced transaction batch processing to handle duplicate transaction errors gracefully, ensuring all transactions are processed and their hashes returned even if duplicates occur.
  • Tests

    • Added tests verifying proper handling of duplicate transaction errors during batch processing.

@jzsfkzm jzsfkzm requested a review from a team as a code owner July 23, 2025 13:46
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 23, 2025

"""

Walkthrough

This update refactors the transaction broadcasting logic in the batch signing client service to handle "transaction already exists in cache" errors gracefully. It introduces a new test suite that mocks dependencies and verifies the service's behavior when duplicate transaction errors occur, ensuring correct transaction hash handling and robust error recovery. Additionally, the service now accepts a connectWithSigner function via constructor for improved client instantiation flexibility. Related signing client providers and services were updated to pass this new parameter.

Changes

File(s) Change Summary
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts Refactored executeTxBatch to handle duplicate transaction errors by computing tx hashes on error; added connectWithSigner parameter to constructor.
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts Added new test suite verifying handling of duplicate transaction errors and correct transaction hash recovery.
apps/api/src/billing/providers/signing-client.provider.ts Updated factory registrations to pass SyncSigningStargateClient.connectWithSigner to BatchSigningClientService constructor.
apps/api/src/billing/services/dedupe-signing-client/dedupe-signing-client.service.ts Modified instantiation of BatchSigningClientService to include SyncSigningStargateClient.connectWithSigner as constructor argument.

Sequence Diagram(s)

sequenceDiagram
    participant TestSuite
    participant BatchSigningClientService
    participant MockedStargateClient

    TestSuite->>BatchSigningClientService: executeTxBatch(transactions)
    loop For each transaction except last
        BatchSigningClientService->>MockedStargateClient: tmBroadcastTxSync(tx)
        alt Error: tx already in cache
            BatchSigningClientService->>BatchSigningClientService: Compute tx hash from bytes
        else Success
            BatchSigningClientService->>BatchSigningClientService: Collect tx hash from response
        end
    end
    BatchSigningClientService->>MockedStargateClient: broadcastTx(lastTx)
    alt Error: tx already in cache
        BatchSigningClientService->>BatchSigningClientService: Compute tx hash from bytes
    else Success
        BatchSigningClientService->>BatchSigningClientService: Collect tx hash from response
    end
    loop For each tx hash
        BatchSigningClientService->>MockedStargateClient: getTx(hash)
        alt Not found
            BatchSigningClientService->>BatchSigningClientService: Return placeholder IndexedTx
        else Found
            BatchSigningClientService->>BatchSigningClientService: Return IndexedTx from client
        end
    end
    BatchSigningClientService-->>TestSuite: Array of IndexedTx (with hashes)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

In the meadow of code where transactions hop,
A duplicate error tried to make us stop.
But now with a hash and a gentle retry,
Our batch leaps forward, no reason to cry.
Tests now ensure the bugs are outmatched—
Hooray for a fix so cleverly patched! 🐇✨
"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-07-25T16_44_59_659Z-debug-0.log

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9088f43 and 035a75e.

📒 Files selected for processing (4)
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (1 hunks)
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts (6 hunks)
  • apps/api/src/billing/providers/signing-client.provider.ts (4 hunks)
  • apps/api/src/billing/services/dedupe-signing-client/dedupe-signing-client.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/api/src/billing/providers/signing-client.provider.ts
  • apps/api/src/billing/services/dedupe-signing-client/dedupe-signing-client.service.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
✨ 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:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

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

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this 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: 1

🧹 Nitpick comments (2)
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts (1)

192-192: Unnecessary filtering of non-null entries.

The filter condition tx => tx !== null is unnecessary since the map function always returns an IndexedTx object (either from getTx or the fallback placeholder). This filtering will never remove any entries.

-return txs.filter(tx => tx !== null);
+return txs;
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (1)

23-86: Setup function follows guidelines well with minor improvements needed.

The setup function is properly positioned and creates comprehensive mocks. However, consider these improvements:

  1. The setup function should accept a parameter even if not used, as per guidelines
  2. The static method override approach works but could be more explicit
-  function setup() {
+  function setup(overrides: {} = {}) {

The static method mocking is functional but consider documenting why this approach is necessary for the SyncSigningStargateClient.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 072ec4d and 7d00702.

📒 Files selected for processing (2)
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (1 hunks)
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts (2 hunks)
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

**/*.{js,jsx,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
🧠 Learnings (1)
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (2)

Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/no-jest-mock.mdc:0-0
Timestamp: 2025-07-21T08:24:24.269Z
Learning: Applies to **/*.spec.{ts,tsx} : Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

Learnt from: jzsfkzm
PR: #1372
File: apps/api/src/dashboard/services/stats/stats.service.ts:0-0
Timestamp: 2025-05-28T20:42:58.200Z
Learning: The user successfully implemented CosmosHttpService with retry logic using axiosRetry, exponential backoff, and proper error handling for Cosmos API calls, replacing direct axios usage in StatsService.

🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

**/*.{js,jsx,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
🧠 Learnings (1)
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (2)

Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/no-jest-mock.mdc:0-0
Timestamp: 2025-07-21T08:24:24.269Z
Learning: Applies to **/*.spec.{ts,tsx} : Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

Learnt from: jzsfkzm
PR: #1372
File: apps/api/src/dashboard/services/stats/stats.service.ts:0-0
Timestamp: 2025-05-28T20:42:58.200Z
Learning: The user successfully implemented CosmosHttpService with retry logic using axiosRetry, exponential backoff, and proper error handling for Cosmos API calls, replacing direct axios usage in StatsService.

⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (7)
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts (3)

2-2: Good addition for hash computation.

The sha256 import is correctly added to support computing transaction hashes when handling cache errors.


147-168: Excellent error handling for duplicate transactions.

The refactored broadcasting logic properly handles "tx already exists in cache" errors by computing the transaction hash from the encoded bytes. The individual transaction processing with try-catch blocks ensures robust error recovery.


177-189: Well-structured fallback IndexedTx object.

The placeholder IndexedTx object includes all required fields with appropriate default values. The use of BigInt for gas fields and proper typing for events and msgResponses arrays is correct.

apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (4)

1-11: Proper use of jest-mock-extended for mocking.

Good adherence to coding guidelines by using jest-mock-extended instead of jest.mock() for creating mocks.


13-21: Well-focused test case for error handling.

The test effectively verifies that the service handles duplicate transaction errors gracefully and returns the correct transaction hash. Direct access to the private method is appropriate for unit testing.


70-77: Excellent error simulation for cache scenarios.

The mock implementations properly simulate the "tx already exists in cache" error for both tmBroadcastTxSync and broadcastTx methods, ensuring comprehensive testing of the error handling logic.


32-68: Comprehensive dependency mocking.

The setup includes thorough mocking of all service dependencies with realistic return values. The configuration mock covers all required keys, and the client mock includes all necessary methods for the test scenario.

@jzsfkzm jzsfkzm force-pushed the bugfixes/1692-handle-tx-in-cache-gracefully branch 4 times, most recently from 10d40e2 to dc7d219 Compare July 24, 2025 15:26
Comment on lines 79 to 81
Object.defineProperty(SyncSigningStargateClient, "connectWithSigner", {
value: jest.fn().mockResolvedValue(mockClient)
});
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion(non-blocking): would be awesome to extract SyncSigningStargateClient.connectWithSigner into dependency and pass it into BatchSigningClientService

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@stalniy Do you mean we should register SyncSigningStargateClient.connectWithSigner in the container? But BatchSigningClientService is not @Injectable at the moment, all the places where we instantiate it, we do it manually at the moment. Should we change that too?

@stalniy
Copy link
Contributor

stalniy commented Jul 25, 2025

@ygrishajev need your review for this PR

@jzsfkzm jzsfkzm force-pushed the bugfixes/1692-handle-tx-in-cache-gracefully branch from dc7d219 to 9088f43 Compare July 25, 2025 12:38
@jzsfkzm jzsfkzm force-pushed the bugfixes/1692-handle-tx-in-cache-gracefully branch from 9088f43 to 035a75e Compare July 25, 2025 16:43
return tx;
}

return {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these changes makes sense. Just one question, why are we returning default values instead of filtering them out? I don't remember in details why we did in the first place.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wasn't sure about that part either, maybe @ygrishajev you can have a second opinion?
My logic was before this we were just filtering out every nullish tx-es, but now we'll have a hash for a tx that is not just in the mempool yet. Questions here are (if not more):

  • should we return mempool tx-es at all?
  • if so, should we fill with defaults?
  • mark such a tx in a way?

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.

tx already in cache

3 participants

Comments