-
Notifications
You must be signed in to change notification settings - Fork 101
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
Reduce usage of RPC providers via relying on them sparingly #2271
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@alfetopito thank you for the review! So multiple things are at play here from what I can see;
I've updated the PR - apologies for the size of it. What I've addressed here are;
What do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of questions in the code, but overall it looks quite good.
The explanations help understand what's going on.
As for the behaviour, briefly tested on FF with multiple networks while disconnected, connected with metamask and via wallet connect.
It all worked great 👍
} | ||
|
||
export const PROVIDERS_RPC_URLS_FIRST_ONLY: Record<SupportedChainId, string> = { | ||
[SupportedChainId.MAINNET]: PROVIDERS_RPC_URLS[SupportedChainId.MAINNET][0], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this PROVIDERS
and PROVIDERS_RPC_URLS
is a bit repetitive. Considere using an IIFE returning the 3 consts, the function would just reduce
the list of supported chains
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this, right? we already have PROVIDERS
?
@@ -26,7 +26,7 @@ const [ledger, ledgerHooks] = initializeConnector<AsyncConnector>( | |||
return new m.Ledger({ | |||
actions, | |||
options: { | |||
rpc: RPC_URLS, | |||
rpc: PROVIDERS_RPC_URLS_FIRST_ONLY, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we could add the comment in the same line as the one of coinbase explaining that ledger allows just one RPC per network
import { ConnectionType } from '@cow/modules/wallet' | ||
import { Web3ReactConnection } from '../types' | ||
import { PROVIDERS } from '@src/custom/constants/networks' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drop the @src/custom
part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
PocketProvider, | ||
AnkrProvider, | ||
} from '@ethersproject/providers' | ||
import * as Sentry from '@sentry/react' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fror this networks
file, i think we should move it to cow-react
maybe wait until my refactor is done. When we "refactor/centralise" sth, is good we remove it from custom
and put it in the right place of cow-react
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good point - I'll update in place for now and wait for your refactor to be finished to move them around.
* These are the network URLs used by the interface when there is not another available source of chain data | ||
* We use this class for type inference. | ||
* | ||
* UrlJsonRpcProvider is an abstract class, therefore we have trouble inferring the type of its constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have trouble
or can't
?
i would think if it's abstract, we don't know the constructor of the children. Is this what you are refering to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote it with my downton abbey glasses apparently 😅 Will rephrase.
[SupportedChainId.GNOSIS_CHAIN]: getProvider(SupportedChainId.GNOSIS_CHAIN), | ||
} | ||
|
||
export const getRpcUrls = (chainId: SupportedChainId) => PROVIDERS[chainId].map((provider) => provider.connection.url) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why exporting this, plus the consts
? I would think one thing or the other, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This exports URLs specifically instead of the provider itself. So for example, when you are using the public provider, we can give you the URL. It is there to support wallets that expect a URL instead of a provider instance, while still allowing for a public provider to be injected.
}, | ||
} | ||
|
||
function constructSentryError(baseError: unknown, { message }: { message: string }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: potencially can be abstracted into something more generic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe some JS doc would be good here, like what is this for. Would this belong more in some common sentry utils or sth?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some comments. I think we can abstract it, but I've stolen it from another part in code; so would love to handle that as a follow up to not mix up refactoring those parts with this change.
errorType: 'provider', | ||
} | ||
|
||
return { baseError, sentryError: constructedError, tags } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why returning also the baseError that is not modified and part of the params?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed it, good point.
|
||
Sentry.captureException(sentryError, { tags }) | ||
|
||
throw new Error(message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you create a sentry error, but throw another error? sentryError
also has the message, wouldn't be simpler to just throw that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this to use the same instance, good point.
|
||
export const providers = { | ||
get mainnet() { | ||
const _providers = getProvider(SupportedChainId.MAINNET) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you have already a const where you pre-calculated this, why not using it? PROVIDERS[SupportedChainId.MAINNET]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated it, good point.
[SupportedChainId.GNOSIS_CHAIN]: PROVIDERS_RPC_URLS[SupportedChainId.GNOSIS_CHAIN][0], | ||
} | ||
|
||
export const providers = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this providers are lowercase?
get mainnet() { | ||
const _providers = getProvider(SupportedChainId.MAINNET) | ||
|
||
if (_providers.length > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn´t this strange to control a casae where we didn´t add the provider for mainnet. Since we do this in a static function, why do we need to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you actually did sth similar for the URLs in coinbase, and we asusme there is at list one URL (i feel is a similar case, but you did sth different)
Should we still keep it opened? |
Current Situation
We are currently relying on a
JsonRpcProvider
, in every instance, via Infura.What
This PR includes a couple of proposals. Code quality can definitely be improved, this iteration is mainly for discussion of the ideas.
window.ethereum
.eth_chainId
(Based onethers.js
discussion here eth_chainId is called every time the provider is used ethers-io/ethers.js#901)InfuraProvider
instead ofJsonRpcProvider
for infura endpoints.ethers.js
claims this would include optimisations on their end, specifically for infura.StaticJsonRpcProvider
instead ofJsonRpcProvider
for non-infura cases.eth_chainId
call.chainId
could change on the fly. However, the way we use these endpoints, it does seem like that is not a possibility (i.e. we create a provider for Gnosis Chain, specifically).Why
Main point for this was trying to figure out amount of calls we are making to infura, as it has been a recent source of pain. During this process, I've noticed that
eth_chainId
andeth_blockNumber
are the highest hit calls, main reason being this information needing to be polled. Specifically,eth_blockNumber
.eth_chainId
.StaticJsonRpcProvider
would stop making this call, albeit definitely should be discussed.Which made me also think about if we could reduce our reliance in general. A recent Slack discussion (https://cowservices.slack.com/archives/C036G0J90BU/p1679062770503109) was related to this topic, as such I've started exploring this PR.
Important Points
I've mainly tested this out as;
After which I have mainly tested;
Which seems to be working, however this is nowhere near enough. I presume, if we desire such a change, we should;
Thank you, and looking forward to hearing what everybody thinks 🐮