Skip to content

[TASK-7669] feat: implement rpc fallback mechanism#630

Closed
kushagrasarathe wants to merge 2 commits intodevelopfrom
fix/rpcs
Closed

[TASK-7669] feat: implement rpc fallback mechanism#630
kushagrasarathe wants to merge 2 commits intodevelopfrom
fix/rpcs

Conversation

@kushagrasarathe
Copy link
Copy Markdown
Contributor

@kushagrasarathe kushagrasarathe commented Jan 15, 2025

implements an automatic fallback mechanism for RPC providers
when the default infura rpc fails, automatically tries to use public rpc endpoints

  • added fallback logic to getChainProvider fn
  • add test coverage for RPC fallback
  • mock necessary dependencies for testing

Summary by CodeRabbit

  • New Features

    • Enhanced blockchain chain provider retrieval with improved error handling and fallback mechanisms.
  • Bug Fixes

    • Improved provider selection logic for different blockchain networks.
  • Tests

    • Added comprehensive unit tests for the chain provider utility function.
    • Implemented mock setup for console warnings during testing.
  • Refactor

    • Migrated chain provider implementation from the ethers library to the peanut SDK.
    • Updated getChainProvider function to be asynchronous.
    • Adjusted provider retrieval in related components to ensure proper asynchronous handling.

- add fallback to public RPC when Infura fails
- add test coverage for RPC fallback
- mock necessary dependencies for testing
@vercel
Copy link
Copy Markdown

vercel bot commented Jan 15, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
peanut-ui ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 15, 2025 7:24pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 15, 2025

Walkthrough

This pull request introduces changes to the blockchain provider utility functions and testing setup. The modifications include mocking the console.warn method in Jest setup, updating the getChainProvider function to use the Peanut SDK instead of Ethers, and adding comprehensive unit tests for the chain provider functionality. The changes focus on improving error handling, provider retrieval, and testing robustness for blockchain-related operations.

Changes

File Change Summary
jest.setup.ts Added mock for console.warn method using jest.fn()
src/utils/chains.utils.ts - Removed Ethers import
- Updated getChainProvider to async function
- Implemented Peanut SDK provider retrieval
- Added fallback and error handling logic
src/utils/__tests__/chains.utils.test.ts Added comprehensive unit tests for getChainProvider function
- Tested Infura RPC provider retrieval
- Verified fallback mechanism
- Checked error handling for non-existent chain IDs
src/components/Create/useCreateLink.tsx Updated call to getChainProvider to await its result
src/components/Request/Pay/Views/Initial.view.tsx Updated call to getChainProvider to await its result

Possibly related PRs

  • Integrate UI with request links #375: The changes in the main PR involve mocking console.warn, which is relevant to the testing enhancements in the src/utils/__tests__/chains.utils.test.ts file that includes unit tests for the getChainProvider function, where warnings are logged during fallback scenarios.
  • Fix build #377: The modifications in the main PR are related to the changes in src/components/Create/useCreateLink.tsx, where the getChainProvider function is now awaited, aligning with the new asynchronous behavior introduced in the main PR.
  • Asserting values #382: The changes in the main PR are connected to the updates in src/components/Request/Pay/Views/Initial.view.tsx, where the createXChainUnsignedTx function now awaits the getChainProvider, reflecting the new asynchronous handling introduced in the main PR.

Suggested reviewers

  • Hugo0

Poem

🐰 A rabbit's tale of chains and mocks,
Where providers dance and testing rocks!
Console warnings silenced with glee,
Peanut SDK sets the network free,
Robust and nimble, our code takes flight! 🚀


📜 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 57c4093 and a53ca34.

📒 Files selected for processing (2)
  • src/components/Create/useCreateLink.tsx (1 hunks)
  • src/components/Request/Pay/Views/Initial.view.tsx (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/components/Request/Pay/Views/Initial.view.tsx (3)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#443
File: src/components/Request/Pay/Views/Initial.view.tsx:293-297
Timestamp: 2024-11-12T09:39:20.720Z
Learning: Routes obtained from `createXChainUnsignedTx` are only valid for 20 seconds, so caching them for reuse is not effective.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:67-74
Timestamp: 2024-11-12T09:39:20.720Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, the functions `getDefaultProvider` and `getTokenContractDetails` used in `fetchTokenSymbol` do not throw errors but can return `undefined`. Additional error handling is unnecessary since this is already handled in the code.
🔇 Additional comments (2)
src/components/Create/useCreateLink.tsx (1)

591-591: LGTM! Provider retrieval is now properly awaited.

The change correctly handles the asynchronous nature of getChainProvider, which is essential for the RPC fallback mechanism to work properly.

src/components/Request/Pay/Views/Initial.view.tsx (1)

46-46: LGTM! Provider retrieval is now properly awaited with fallback.

The change correctly handles the asynchronous nature of both getChainProvider and the fallback to peanut.getDefaultProvider. This implementation aligns with the RPC fallback mechanism requirements.

Note: Based on past learnings, remember that routes obtained from createXChainUnsignedTx are only valid for 20 seconds.


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.

@notion-workspace
Copy link
Copy Markdown

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

🧹 Nitpick comments (2)
src/utils/chains.utils.ts (1)

29-35: Test the public RPC connection before returning the provider

Currently, when falling back to the public RPC, the connection is not tested before returning the provider. Similar to the default provider, consider testing the connection with getNetwork() to ensure the public RPC is functional.

Apply this diff to test the fallback provider:

34-            return peanut.getDefaultProvider(publicRpcUrl)
+            const fallbackProvider = new peanut.JsonRpcProvider(publicRpcUrl)
+            await fallbackProvider.getNetwork() // Test the connection
+            return fallbackProvider

This ensures that if the public RPC is also unavailable, the function will throw an error appropriately.

jest.setup.ts (1)

17-19: Nitpick: Consolidate console.warn mocking in the global console object

For consistency, include warn: jest.fn(), in the initial global.console assignment instead of reassigning global.console.warn separately. This keeps all console mocks in one place and makes the setup cleaner.

Apply this diff:

     global.console = {
         ...console,
         // Uncomment to ignore a specific log level
         // log: jest.fn(),
         debug: jest.fn(),
+        warn: jest.fn(),
         // error: jest.fn(),
     }
 
-// mock console.warn
-global.console.warn = jest.fn()
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c030da2 and 57c4093.

📒 Files selected for processing (3)
  • jest.setup.ts (1 hunks)
  • src/utils/__tests__/chains.utils.test.ts (1 hunks)
  • src/utils/chains.utils.ts (2 hunks)

throw new Error(`No public RPC URL found for chain ${chainId}`)
}

return peanut.getDefaultProvider(publicRpcUrl)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical Issue: peanut.getDefaultProvider may not accept an RPC URL

In the fallback scenario, you're calling peanut.getDefaultProvider(publicRpcUrl). However, peanut.getDefaultProvider might not accept an RPC URL as a parameter—it may expect a chain ID or network name instead. This could cause the fallback to fail or return an incorrect provider.

To ensure proper functionality, verify that peanut.getDefaultProvider can accept an RPC URL. If it doesn't, use the appropriate method to create a provider from an RPC URL. Additionally, test the connection after obtaining the fallback provider to confirm it's operational.

Apply this diff to correct the code:

34             return peanut.getDefaultProvider(publicRpcUrl)
+            const fallbackProvider = new peanut.JsonRpcProvider(publicRpcUrl)
+            await fallbackProvider.getNetwork() // Test the connection
+            return fallbackProvider

Ensure that peanut.JsonRpcProvider or the correct constructor is used based on the Peanut SDK's API.

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

default: { http: ['some-url'] },
},
}
jest.spyOn(chains, 'find').mockReturnValueOnce(chainWithoutPublicRpc)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical Issue: Cannot use jest.spyOn on array prototype methods

You're attempting to mock chains.find using jest.spyOn(chains, 'find'). However, find is a prototype method of JavaScript arrays, and jest.spyOn cannot be used on built-in prototype methods. This means the mock won't work as intended.

To fix this, replace the chains array with a custom one for this test or remock the module to provide the desired chain configuration.

Apply this diff to adjust your test setup:

-        jest.spyOn(chains, 'find').mockReturnValueOnce(chainWithoutPublicRpc)
+        // Replace the chains array with one that has the chain without public RPC
+        (chains as any) = [
+            chainWithoutPublicRpc,
+        ]

Alternatively, remock the chains module:

+        jest.mock('@/constants/chains.consts', () => ({
+            chains: [
+                chainWithoutPublicRpc,
+            ],
+        }))

Ensure you reset the module after the test to avoid affecting other tests:

afterEach(() => {
    jest.resetModules()
})

Comment on lines +20 to +25
// Try default (Infura) provider first
try {
const defaultProvider = await peanut.getDefaultProvider(chainId)
await defaultProvider.getNetwork() // Test the connection
return defaultProvider
} catch (error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Q: Im confused - getDefaultProvider finds a public provider first, no?

Comment on lines +37 to +47
it('should successfully return provider when Infura RPC works', async () => {
// setup successful infura response
mockProvider.getNetwork.mockResolvedValueOnce({ chainId: 1 })
;(peanut.getDefaultProvider as jest.Mock).mockResolvedValueOnce(mockProvider)

const provider = await getChainProvider('1')

expect(provider).toBe(mockProvider)
expect(peanut.getDefaultProvider).toHaveBeenCalledWith('1')
expect(mockProvider.getNetwork).toHaveBeenCalled()
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: Ideally we can test for infura being in the rpc url - that way we're sure we got an infura RPC

senderAddress: string
}) {
const provider = getChainProvider(tokenData.chainId) || (await peanut.getDefaultProvider(tokenData.chainId))
const provider = (await getChainProvider(tokenData.chainId)) || (await peanut.getDefaultProvider(tokenData.chainId))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Q: idg this, isn't getChainProvider just a wrapper of getDefaultProvider right now? What logic does this line make?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

valid, dumb me, fixing this 🫠

@Hugo0 Hugo0 deleted the branch develop July 3, 2025 18:25
@Hugo0 Hugo0 closed this Jul 3, 2025
@Hugo0 Hugo0 deleted the fix/rpcs branch July 3, 2025 18:26
@Hugo0 Hugo0 restored the fix/rpcs branch July 3, 2025 18:26
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.

2 participants