Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
cca8f81
Extend createServicePolicy to support live network status
mcmire Nov 14, 2025
6a3cff1
Fix tests
mcmire Nov 15, 2025
c08f398
Add more tests
mcmire Nov 17, 2025
5e0e3e1
No need for getLastInnerFailureReason
mcmire Nov 17, 2025
e2eba7a
Fix an issue with onAvailable
mcmire Nov 17, 2025
246b2b5
Reduce the diff
mcmire Nov 17, 2025
199bb79
Fix tests
mcmire Nov 17, 2025
ff6d832
Use a quasi-enum for the availability status
mcmire Nov 17, 2025
fa66813
Fix test
mcmire Nov 17, 2025
9d090e9
Revamp NetworkController RPC endpoint events
mcmire Nov 14, 2025
0da865b
Remove this comment
mcmire Nov 17, 2025
b3909af
Add 'degraded' status
mcmire Nov 17, 2025
6b628d7
Use similar terminology as in createServicePolicy
mcmire Nov 17, 2025
4a3985a
Merge branch 'update-create-service-policy' into update-network-contr…
mcmire Nov 17, 2025
2d38446
Adjust createServicePolicy as well
mcmire Nov 17, 2025
3d8da80
Adjust createServicePolicy as well
mcmire Nov 17, 2025
7860897
Merge branch 'update-create-service-policy' into update-network-contr…
mcmire Nov 18, 2025
f67839a
Update some of the terminology
mcmire Nov 18, 2025
110cb0b
Update more of the terminology
mcmire Nov 18, 2025
b16597a
RpcEndpointUnvailable -> RpcEndpointUnavailable
mcmire Nov 18, 2025
137c3d7
Merge branch 'main' into update-network-controller-rpc-endpoint-events
mcmire Nov 19, 2025
cb498e3
Address Cursor comment
mcmire Nov 19, 2025
cdd8491
Make the RPC endpoint event tests more realistic, and address Cursor …
mcmire Nov 19, 2025
73017d1
Reword JSDoc for events, remove endpointUrl from chainUnavailable event
mcmire Nov 20, 2025
7de4def
Merge branch 'main' into update-network-controller-rpc-endpoint-events
mcmire Nov 20, 2025
026ce00
Use the primaryEndpointUrl from the Cockatiel event in the messenger …
mcmire Nov 20, 2025
0e13332
Merge branch 'main' into update-network-controller-rpc-endpoint-events
mcmire Nov 21, 2025
74d9d0f
Remove RpcService.getLastInnerFailureReason, use lastError directly
mcmire Nov 21, 2025
bbbfa9c
Remove redundant tag in log
mcmire Nov 21, 2025
4f9d84b
data -> context
mcmire Nov 21, 2025
1862024
Remove unused utility type
mcmire Nov 21, 2025
2f29875
Tweak log statement
mcmire Nov 21, 2025
827696f
Tweak comment
mcmire Nov 21, 2025
72de1d6
Revert log change
mcmire Nov 21, 2025
0f55384
Add comment for why we are ignoring 'isolated'
mcmire Nov 21, 2025
067a807
refactor(network-controller): improve RPC service chain configuration
cryptodev-2s Nov 25, 2025
4b57f32
refactor(network-controller): replace magic number with calculated co…
cryptodev-2s Nov 25, 2025
056703f
test(network-controller): rollback test description change
cryptodev-2s Nov 25, 2025
321ff7c
Group RPC endpoint event tests by failover enabled/disabled
cryptodev-2s Nov 25, 2025
7b9c736
docs: add JSDoc for getError helper in createNetworkClient
cryptodev-2s Nov 25, 2025
2c35648
refactor: remove primaryEndpointUrl from chain-level RPC events
cryptodev-2s Nov 25, 2025
30a9486
docs: clarify event payload changes in network-controller changelog
cryptodev-2s Nov 26, 2025
4e7a37a
fix: add undefined check for error in onServiceBreak handler
cryptodev-2s Nov 26, 2025
61bdbbc
refactor: improve type safety for getError function
cryptodev-2s Nov 26, 2025
9fea617
fix: prevent race condition in onBreak chain status check
cryptodev-2s Nov 26, 2025
e4459ee
revert: remove previousStatus check that introduced race condition
cryptodev-2s Nov 26, 2025
c59898d
test: fix test to properly verify degraded then recover scenario
cryptodev-2s Nov 26, 2025
bcc840f
Remove primaryEndpointUrl from onBreak, onDegraded, and onAvailable e…
cryptodev-2s Nov 26, 2025
3918d08
Remove endpointUrl from chain-level RPC events
cryptodev-2s Nov 26, 2025
916a0e2
Fix typo: correct tertiary endpoint URL in test
cryptodev-2s Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/network-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `NetworkController:rpcEndpointChainAvailable` messenger event ([#7166](https://github.com/MetaMask/core/pull/7166))
- This is a counterpart to the (new) `NetworkController:rpcEndpointChainUnavailable` and `NetworkController:rpcEndpointChainDegraded` events, but is published when a successful request to an endpoint within a chain of endpoints is made either initially or following a previously established degraded or unavailable status.

### Changed

- **BREAKING:** Split up and update payload data for `NetworkController:rpcEndpointDegraded` and `NetworkController:rpcEndpointUnavailable` ([#7166](https://github.com/MetaMask/core/pull/7166))
- `NetworkController:rpcEndpointDegraded` and `NetworkController:rpcEndpointUnavailable` still exist and retain the same behavior as before.
- New events are `NetworkController:rpcEndpointChainDegraded` and `NetworkController:rpcEndpointChainUnavailable`, and are designed to represent an entire chain of endpoints. They are also guaranteed to not be published multiple times in a row. In particular, `NetworkController:rpcEndpointChainUnavailable` is published only after trying all of the endpoints for a chain and when the underlying circuit for the last endpoint breaks, not as each primary's or failover's circuit breaks.
- The event payloads have been changed:
- For individual endpoint events (`NetworkController:rpcEndpointUnavailable`, `NetworkController:rpcEndpointDegraded`): `failoverEndpointUrl` has been removed, and `primaryEndpointUrl` has been added. In addition, `networkClientId` has been added to the payload.
- For chain-level events (`NetworkController:rpcEndpointChainUnavailable`, `NetworkController:rpcEndpointChainDegraded`, `NetworkController:rpcEndpointChainAvailable`): These include `chainId`, `networkClientId`, and event-specific fields (e.g., `error`, `endpointUrl`) but do not include `primaryEndpointUrl`. Consumers can derive endpoint information from the `networkClientId` using `NetworkController:getNetworkClientById` or `NetworkController:getNetworkConfigurationByNetworkClientId`.
- **BREAKING:** Rename and update payload data for `NetworkController:rpcEndpointRequestRetried` ([#7166](https://github.com/MetaMask/core/pull/7166))
- This event is now called `NetworkController:rpcEndpointRetried`.
- The event payload has been changed as well: `failoverEndpointUrl` has been removed, and `primaryEndpointUrl` has been added. In addition, `networkClientId` and `attempt` have been added to the payload.
- **BREAKING:** Update `AbstractRpcService`/`RpcServiceRequestable` to remove `{ isolated: true }` from the `onBreak` event data type ([#7166](https://github.com/MetaMask/core/pull/7166))
- This represented the error produced when `isolate` is called on a Cockatiel circuit breaker policy. This never happens for our service (we use `isolate` internally, but this error is suppressed and cannot trigger `onBreak`)
- Move peer dependencies for controller and service packages to direct dependencies ([#7209](https://github.com/MetaMask/core/pull/7209))
- The dependencies moved are:
- `@metamask/error-reporting-service` (^3.0.0)
Expand Down
1 change: 1 addition & 0 deletions packages/network-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"@types/jest-when": "^2.7.3",
"@types/lodash": "^4.14.191",
"@types/node-fetch": "^2.6.12",
"cockatiel": "^3.1.2",
"deep-freeze-strict": "^1.1.1",
"deepmerge": "^4.2.2",
"jest": "^27.5.1",
Expand Down
157 changes: 145 additions & 12 deletions packages/network-controller/src/NetworkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,25 +443,112 @@ export type NetworkControllerNetworkRemovedEvent = {
};

/**
* `rpcEndpointUnavailable` is published after an attempt to make a request to
* an RPC endpoint fails too many times in a row (because of a connection error
* or an unusable response).
* `NetworkController:rpcEndpointChainUnavailable` is published when, after
* trying all endpoints in an endpoint chain, the last failover reaches a
* maximum number of consecutive 5xx responses, breaking the underlying circuit.
*
* In other words, this event will not be published if a failover is available,
* even if the primary is not.
*
* @param payload - The event payload.
* @param payload.chainId - The target network's chain ID.
* @param payload.error - The last error produced by the last failover in the
* endpoint chain.
* @param payload.networkClientId - The target network's client ID.
*/
export type NetworkControllerRpcEndpointChainUnavailableEvent = {
type: 'NetworkController:rpcEndpointChainUnavailable';
payload: [
{
chainId: Hex;
error: unknown;
networkClientId: NetworkClientId;
},
];
};

/**
* `NetworkController:rpcEndpointUnavailable` is published when any
* endpoint in an endpoint chain reaches a maximum number of consecutive 5xx
* responses, breaking the underlying circuit.
*
* In other words, this event will be published if a primary is not available,
* even if a failover is.
*
* @param payload - The event payload.
* @param payload.chainId - The target network's chain ID.
* @param payload.endpointUrl - The URL of the endpoint which reached the
* maximum number of consecutive 5xx responses. You can compare this to
* `primaryEndpointUrl` to know whether it was a failover or a primary.
* @param payload.error - The last error produced by the endpoint.
* @param payload.networkClientId - The target network's client ID.
* @param payload.primaryEndpointUrl - The endpoint chain's primary URL.
*/
export type NetworkControllerRpcEndpointUnavailableEvent = {
type: 'NetworkController:rpcEndpointUnavailable';
payload: [
{
chainId: Hex;
endpointUrl: string;
failoverEndpointUrl?: string;
error: unknown;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};

/**
* `rpcEndpointDegraded` is published after a request to an RPC endpoint
* responds successfully but takes too long.
* `NetworkController:rpcEndpointChainDegraded` is published for any of the
* endpoints in an endpoint chain when one of the following two conditions hold
* (and the chain is not already in a degraded state):
*
* 1. A successful (2xx) request, even after being retried, cannot be made to
* the endpoint.
* 2. A successful (2xx) request can be made to the endpoint, but it takes
* longer than expected to complete.
*
* Note that this event will be published even if there are local connectivity
* issues which prevent requests from being initiated. This is intentional.
*
* @param payload - The event payload.
* @param payload.chainId - The target network's chain ID.
* @param payload.error - The last error produced by the endpoint (or
* `undefined` if the request was slow).
* @param payload.networkClientId - The target network's client ID.
*/
export type NetworkControllerRpcEndpointChainDegradedEvent = {
type: 'NetworkController:rpcEndpointChainDegraded';
payload: [
{
chainId: Hex;
error: unknown;
networkClientId: NetworkClientId;
},
];
};

/**
*
* `NetworkController:rpcEndpointDegraded` is published for any of the endpoints
* in an endpoint chain when:
*
* 1. A successful (2xx) request, even after being retried, cannot be made to
* the endpoint.
* 2. A successful (2xx) request can be made to the endpoint, but it takes
* longer than expected to complete.
*
* Note that this event will be published even if there are local connectivity
* issues which prevent requests from being initiated. This is intentional.
*
* @param payload - The event payload.
* @param payload.chainId - The target network's chain ID.
* @param payload.endpointUrl - The URL of the endpoint for which requests
* failed or were slow to complete. You can compare this to `primaryEndpointUrl`
* to know whether it was a failover or a primary.
* @param payload.error - The last error produced by the endpoint (or
* `undefined` if the request was slow).
* @param payload.networkClientId - The target network's client ID.
* @param payload.primaryEndpointUrl - The endpoint chain's primary URL.
*/
export type NetworkControllerRpcEndpointDegradedEvent = {
type: 'NetworkController:rpcEndpointDegraded';
Expand All @@ -470,20 +557,59 @@ export type NetworkControllerRpcEndpointDegradedEvent = {
chainId: Hex;
endpointUrl: string;
error: unknown;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};

/**
* `rpcEndpointRequestRetried` is published after a request to an RPC endpoint
* is retried following a connection error or an unusable response.
* `NetworkController:rpcEndpointChainAvailable` is published in one of two
* cases:
*
* 1. The first time that a 2xx request is made to any of the endpoints in an
* endpoint chain.
* 2. When requests to any of the endpoints previously failed (placing the
* endpoint in a degraded or unavailable status), but are now succeeding again.
*
* @param payload - The event payload.
* @param payload.chainId - The target network's chain ID.
* @param payload.networkClientId - The target network's client ID.
*/
export type NetworkControllerRpcEndpointRequestRetriedEvent = {
type: 'NetworkController:rpcEndpointRequestRetried';
export type NetworkControllerRpcEndpointChainAvailableEvent = {
type: 'NetworkController:rpcEndpointChainAvailable';
payload: [
{
chainId: Hex;
networkClientId: NetworkClientId;
},
];
};

/**
* `NetworkController:rpcEndpointRetried` is published before a request to any
* endpoint in an endpoint chain is retried.
*
* This is mainly useful for tests.
*
* @param payload - The event payload.
* @param payload.attempt - The current attempt counter for the endpoint
* (starting from 0).
* @param payload.chainId - The target network's chain ID.
* @param payload.endpointUrl - The URL of the endpoint being retried.
* @param payload.networkClientId - The target network's client ID.
* @param payload.primaryEndpointUrl - The endpoint chain's primary URL.
* @see {@link RpcService} for the list of retriable errors.
*/
export type NetworkControllerRpcEndpointRetriedEvent = {
type: 'NetworkController:rpcEndpointRetried';
payload: [
{
endpointUrl: string;
attempt: number;
chainId: Hex;
endpointUrl: string;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};
Expand All @@ -496,9 +622,12 @@ export type NetworkControllerEvents =
| NetworkControllerInfuraIsUnblockedEvent
| NetworkControllerNetworkAddedEvent
| NetworkControllerNetworkRemovedEvent
| NetworkControllerRpcEndpointChainUnavailableEvent
| NetworkControllerRpcEndpointUnavailableEvent
| NetworkControllerRpcEndpointChainDegradedEvent
| NetworkControllerRpcEndpointDegradedEvent
| NetworkControllerRpcEndpointRequestRetriedEvent;
| NetworkControllerRpcEndpointChainAvailableEvent
| NetworkControllerRpcEndpointRetriedEvent;

/**
* All events that {@link NetworkController} calls internally.
Expand Down Expand Up @@ -2800,6 +2929,7 @@ export class NetworkController extends BaseController<
autoManagedNetworkClientRegistry[NetworkClientType.Infura][
addedRpcEndpoint.networkClientId
] = createAutoManagedNetworkClient({
networkClientId: addedRpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Infura,
chainId: networkFields.chainId,
Expand All @@ -2818,6 +2948,7 @@ export class NetworkController extends BaseController<
autoManagedNetworkClientRegistry[NetworkClientType.Custom][
addedRpcEndpoint.networkClientId
] = createAutoManagedNetworkClient({
networkClientId: addedRpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Custom,
chainId: networkFields.chainId,
Expand Down Expand Up @@ -2980,6 +3111,7 @@ export class NetworkController extends BaseController<
return [
rpcEndpoint.networkClientId,
createAutoManagedNetworkClient({
networkClientId: rpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Infura,
network: infuraNetworkName,
Expand All @@ -2999,6 +3131,7 @@ export class NetworkController extends BaseController<
return [
rpcEndpoint.networkClientId,
createAutoManagedNetworkClient({
networkClientId: rpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Custom,
chainId: networkConfiguration.chainId,
Expand Down
Loading
Loading