-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
Create and expose collection of network clients #1439
Conversation
ff0feb3
to
afebca5
Compare
afebca5
to
fbde98b
Compare
38df17a
to
6d11b2f
Compare
In order for users to make requests to multiple networks simultaneously, we need to phase out the concept of a single active network in the network controller in favor of a collection of networks (active or otherwise). This commit is the first step in making this happen. To this end, this commit: - Adds the concept of an "auto-managed network client". This is an object that has the same exact interface as a network client — that is, it exposes a provider and block tracker — except that the network client doesn't spring into existence until an attempt is made to use the provider or block tracker in some way. This prevents network requests from occurring prematurely. - Adds a registry to hold auto-managed network clients. This registry will be prepopulated with networks we've built in to MetaMask as well as any custom networks that already exist in state under `networkConfigurations`. - Adds a new method `getNetworkClients` which returns the contents of the registry. - Update the logic that is executed when `initializeProvider`, `setProviderType`, `setActiveNetwork`, or `resetConnection` is called so that the "active network client" — i.e. the targets of the provider and block tracker proxy — is merely set based on some existing network client in the registry instead of being recreated each time. - Updates `upsertNetworkConfiguration` and `removeNetworkConfiguration` to either a) create a new network client in the event that a new network configuration is added and add it to the network client registry or b) destroy and remove an existing network client from the registry then create a new one in the event that the chain ID for an existing network configuration is updated.
6d11b2f
to
1e2ba98
Compare
@@ -353,42 +420,57 @@ export class NetworkController extends BaseControllerV2< | |||
this.#previousProviderConfig = this.state.providerConfig; | |||
} | |||
|
|||
#configureProvider( |
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 method effectively turned into #createAutoManagedNetworkClientRegistry
.
this.messagingSystem.publish('NetworkController:networkDidChange'); | ||
await this.lookupNetwork(); | ||
} | ||
|
||
#registerProvider() { |
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 consolidated this method into #selectNetwork
.
} | ||
} | ||
|
||
#setupInfuraProvider(type: InfuraNetworkType) { |
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.
The code in this and the next method is now split up into two methods. The code to create the network client is now in #createAutoManagedNetworkClientRegistry
and the code to update the provider is now in #selectNetwork
.
): Promise<string> { | ||
assertIsStrictHexString(chainId); | ||
const sanitizedNetworkConfiguration = ( |
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 were technically doing this before by destructuring the object that this method takes, but that approach meant that properties of the network configuration object that were not technically provided ended up as undefined
when put into networkConfigurations
. The code here is essentially equivalent to Lodash's pick
function.
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.
Makes sense! Potentially simpler to use the argument as-is and throw if extra properties are there (safer too, as we'd be informed about these properties being ignored rather than them being silently dropped). But that would be better as a separate PR, if we did want to go that route.
/** | ||
* Handles mocking JSON-requests sent to the network. | ||
*/ | ||
class MockedNetwork { |
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.
* | ||
* @returns The list of known network clients. | ||
*/ | ||
getNetworkClients(): AutoManagedNetworkClient<NetworkClientConfiguration>[] { |
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.
Hmm, do you think a list is the right data structure to use here? I'm just wondering how this is likely to be used. Maybe having them keyed by something (e.g. network name for built-in, or id for custom) would be better.
Presumably, in most places where this is called, the caller is going to be looking for a specific network client. Keying it by whatever unique identifier the caller is likely to have would probably make this easier to use.
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.
Right. The first version of this method was called getNetworkClientsById
and returned an object keyed by an identifier, which for Infura networks would look like infura||<network>
and for custom networks would look like custom||<chainId>||<lowercased rpcUrl>
or custom||<network configuration ID>
, depending on where it came from 1.
Ultimately I wasn't sure how we will end up using this collection and figured that once we had more information we could tweak this. So I went with an array for now. But, an object would definitely be more versatile. I'll play around with this some more.
Footnotes
-
Custom networks aren't always associated with a network configuration ID, so we can't always use that in the identifier (because the network controller can be instantiated with a
providerConfig
that has nothing to do with a built-in network or a network innetworkConfigurations
). ↩
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.
Custom networks aren't always associated with a network configuration ID
They are if you consider just how extension and mobile are using this controller. We can consider it a breaking change of this API, but "supporting custom networks specified via provider config that don't correspond with network configurations" is not a feature we're supporting intentionally. If anything it's a bug.
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.
Okay, I've changed this method to return an object rather than an array: 96c4229
Co-authored-by: Mark Stacey <[email protected]>
packages/network-controller/src/create-auto-managed-network-client.ts
Outdated
Show resolved
Hide resolved
packages/network-controller/src/create-auto-managed-network-client.ts
Outdated
Show resolved
Hide resolved
packages/network-controller/src/create-auto-managed-network-client.test.ts
Show resolved
Hide resolved
This reverts commit edd4a8bb1940558e5f0ebda743c92eb8b41fa8e2.
- Extract code that builds a network client ID - Refactor `#createAutoManagedNetworkClientRegistry` to avoid loop - Use full network client IDs in registry so that we can change `getNetworkClients()`
networkConfigurations: { | ||
testNetworkConfiguration: { | ||
id: 'testNetworkConfiguration', | ||
describe('if a provider has not been set', () => { |
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.
The functionality tested here already exists, but as I was updating the JSDocs for rollbackToPreviousProvider
, I noticed that they referred to this behavior. I wanted to ensure that I wasn't breaking anything, so I backfilled them. I also grouped the existing tests under a describe
— that's what's causing the large diff here. I didn't change any of the existing tests, though, so if you remove this describe
and then ungroup the tests within the next one, then you shouldn't see any differences in the diff.
@Gudahtt I believe I've addressed all of your comments above. |
if (typeof infuraNetworkOrProviderConfig === 'string') { | ||
return `infura||${infuraNetworkOrProviderConfig}` as const; | ||
} | ||
return `infura||${infuraNetworkOrProviderConfig.type}` as const; |
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.
How important is it that we use a composite ID?
I'm wondering because I'm hoping that we'll eventually migrate the built-in networks to be more similar to the custom networks (one type of network client, one middleware stack, etc., see #1279), at which point we presumably won't have a need for this custom||
prefix on each ID.
And until then, we don't have to worry about ID conflicts. The UUIDs we create for custom networks will never conflict with the short built-in network names.
Perhaps dropping the composite ID now would save us the effort of removing it in a migration later?
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'd also make it a bit simpler to access network clients in cases where we don't already have the network client ID. We could do soemthing like networkClients[providerConfig.type || providerConfig.id]
, no need to construct the ID each time.
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 don't really need the prefix to be able to tell what type of network client it is, that's true. One benefit to using a prefix that I can think of is that it allows the type of a built-in network client ID to be clearly different from the type of a custom network client ID — and actually, it allows a type to be assigned to the network client ID at all. If we drop the prefix, then the type of a custom network client ID is just string
. At that point, any kind of network client ID itself, at least from a consumer perspective, will end up being string
, whether Infura or not.
Maybe that's fine though. Network configuration IDs are just string
s and we're okay with that. I've made this change here: 9e67774
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.
Right... yeah this does make type narrowing more challenging. It's still possible for us to narrow from string
to InfuraNetworkType
though at least. We'd need to compare with each entry rather than just look at the prefix. This seems OK though.
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.
Looks good! All that's left are nits, plus that one question about the ID. I'd like to at least hear your thoughts about the ID before proceeding but otherwise I'm ready to approve.
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.
LGTM!
@@ -296,8 +530,12 @@ export class NetworkController extends BaseControllerV2< | |||
|
|||
#providerProxy: ProviderProxy | undefined; | |||
|
|||
#provider: ProxyWithAccessibleTarget<Provider> | undefined; |
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.
What is this doing? It looks like we set it but never use it? And its private so it couldn't used externally? cc @mcmire
Create and expose collection of network clients In order for users to make requests to multiple networks simultaneously, we need to phase out the concept of a single active network in the network controller in favor of a collection of networks (active or otherwise). This commit is the first step in making this happen. To this end, this commit: - Adds the concept of an "auto-managed network client". This is an object that has the same exact interface as a network client — that is, it exposes a provider and block tracker — except that the network client doesn't spring into existence until an attempt is made to use the provider or block tracker in some way. - Adds a registry to hold auto-managed network clients. This registry will be prepopulated with networks we've built in to MetaMask as well as any custom networks that already exist in state under `networkConfigurations`. - Adds a new method `getNetworkClientsById` which returns the contents of the registry, keyed by identifier. - Update the logic that is executed when `initializeProvider`, `setProviderType`, `setActiveNetwork`, or `resetConnection` is called so that the "active network client" — i.e. the targets of the provider and block tracker proxy — is merely set based on some existing network client in the registry instead of being recreated each time. - Updates `upsertNetworkConfiguration` and `removeNetworkConfiguration` to either a) create a new network client in the event that a new network configuration is added and add it to the network client registry or b) destroy and remove an existing network client from the registry then create a new one in the event that the chain ID for an existing network configuration is updated. Co-authored-by: Mark Stacey <[email protected]>
Create and expose collection of network clients In order for users to make requests to multiple networks simultaneously, we need to phase out the concept of a single active network in the network controller in favor of a collection of networks (active or otherwise). This commit is the first step in making this happen. To this end, this commit: - Adds the concept of an "auto-managed network client". This is an object that has the same exact interface as a network client — that is, it exposes a provider and block tracker — except that the network client doesn't spring into existence until an attempt is made to use the provider or block tracker in some way. - Adds a registry to hold auto-managed network clients. This registry will be prepopulated with networks we've built in to MetaMask as well as any custom networks that already exist in state under `networkConfigurations`. - Adds a new method `getNetworkClientsById` which returns the contents of the registry, keyed by identifier. - Update the logic that is executed when `initializeProvider`, `setProviderType`, `setActiveNetwork`, or `resetConnection` is called so that the "active network client" — i.e. the targets of the provider and block tracker proxy — is merely set based on some existing network client in the registry instead of being recreated each time. - Updates `upsertNetworkConfiguration` and `removeNetworkConfiguration` to either a) create a new network client in the event that a new network configuration is added and add it to the network client registry or b) destroy and remove an existing network client from the registry then create a new one in the event that the chain ID for an existing network configuration is updated. Co-authored-by: Mark Stacey <[email protected]>
Explanation
In order for users to make requests to multiple networks simultaneously, we need to phase out the concept of a single active network in the network controller in favor of a collection of networks (active or otherwise). This commit is the first step in making this happen.
To this end, this commit:
networkConfigurations
.getNetworkClients
which returns the contents of the registry.initializeProvider
,setProviderType
,setActiveNetwork
, orresetConnection
is called so that the "active network client" — i.e. the targets of the provider and block tracker proxy — is merely set based on some existing network client in the registry instead of being recreated each time.upsertNetworkConfiguration
andremoveNetworkConfiguration
to either a) create a new network client in the event that a new network configuration is added and add it to the network client registry or b) destroy and remove an existing network client from the registry then create a new one in the event that the chain ID for an existing network configuration is updated.References
Fixes #1045.
Changelog
@metamask/network-controller
getNetworkClientsById
methodupsertNetworkConfiguration
to keep the network client registry up to date with changes to the set of network configurationsChecklist