Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 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
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
14 changes: 14 additions & 0 deletions packages/network-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,22 @@ 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:rpcEndpointUnavailable` 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 for all events have been changed as well: `failoverEndpointUrl` has been renamed to `endpointUrl`, and `endpointUrl` has been renamed to `primaryEndpointUrl`. In addition, `networkClientId` has been added to the payload.
- **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 renamed to `endpointUrl`, and `endpointUrl` has been renamed to `primaryEndpointUrl`. 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, which we don't do (at least, not in the way it is designed to be called)
- 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
167 changes: 156 additions & 11 deletions packages/network-controller/src/NetworkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,25 +443,119 @@ 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.
* @param payload.primaryEndpointUrl - The endpoint chain's primary URL.
*/
export type NetworkControllerRpcEndpointChainUnavailableEvent = {
type: 'NetworkController:rpcEndpointChainUnavailable';
payload: [
{
chainId: Hex;
error: unknown;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};
Copy link

Choose a reason for hiding this comment

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

Bug: Missing endpointUrl in chain unavailable event payload

The NetworkController:rpcEndpointChainUnavailable event payload type definition and usage omit the endpointUrl property. This is inconsistent with all other similar events (ChainDegraded, ChainAvailable, Unavailable) which include it, and contradicts the PR discussion implying uniform payloads. Including endpointUrl is useful for identifying the specific failover endpoint that caused the chain to break.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is intentional, as per the discussion above.


/**
* `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.endpointUrl - The URL of the endpoint for which requests
* failed or were slow to complete.
* @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 NetworkControllerRpcEndpointChainDegradedEvent = {
type: 'NetworkController:rpcEndpointChainDegraded';
payload: [
{
chainId: Hex;
endpointUrl: string;
error: unknown;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};

/**
*
* `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 +564,64 @@ 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.endpointUrl - The URL of the endpoint which meets either of
* the above conditions.
* @param payload.networkClientId - The target network's client ID.
* @param payload.primaryEndpointUrl - The endpoint chain's primary URL.
*/
export type NetworkControllerRpcEndpointRequestRetriedEvent = {
type: 'NetworkController:rpcEndpointRequestRetried';
export type NetworkControllerRpcEndpointChainAvailableEvent = {
type: 'NetworkController:rpcEndpointChainAvailable';
payload: [
{
chainId: Hex;
endpointUrl: string;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};

/**
* `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: [
{
attempt: number;
chainId: Hex;
endpointUrl: string;
networkClientId: NetworkClientId;
primaryEndpointUrl: string;
},
];
};
Expand All @@ -496,9 +634,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 +2941,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 +2960,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 +3123,7 @@ export class NetworkController extends BaseController<
return [
rpcEndpoint.networkClientId,
createAutoManagedNetworkClient({
networkClientId: rpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Infura,
network: infuraNetworkName,
Expand All @@ -2999,6 +3143,7 @@ export class NetworkController extends BaseController<
return [
rpcEndpoint.networkClientId,
createAutoManagedNetworkClient({
networkClientId: rpcEndpoint.networkClientId,
networkClientConfiguration: {
type: NetworkClientType.Custom,
chainId: networkConfiguration.chainId,
Expand Down
Loading
Loading