Skip to content

Commit

Permalink
Add auto-detected static network support to providers and allow custo…
Browse files Browse the repository at this point in the history
…mizing socket provider options (ethers-io#4199, ethers-io#4418, ethers-io#4441).
  • Loading branch information
ricmoo authored and Woodpile37 committed Jan 14, 2024
1 parent 51f6cb7 commit e777964
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 28 deletions.
6 changes: 4 additions & 2 deletions src.ts/providers/provider-ipcsocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { connect } from "net";
import { SocketProvider } from "./provider-socket.js";

import type { Socket } from "net";

import type { JsonRpcApiProviderOptions } from "./provider-jsonrpc.js";
import type { Networkish } from "./network.js";


Expand Down Expand Up @@ -35,8 +37,8 @@ export class IpcSocketProvider extends SocketProvider {
*/
get socket(): Socket { return this.#socket; }

constructor(path: string, network?: Networkish) {
super(network);
constructor(path: string, network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(network, options);
this.#socket = connect(path);

this.socket.on("ready", async () => {
Expand Down
70 changes: 49 additions & 21 deletions src.ts/providers/provider-jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export type DebugEventJsonRpcApiProvider = {
*/
export type JsonRpcApiProviderOptions = {
polling?: boolean;
staticNetwork?: null | Network;
staticNetwork?: null | boolean | Network;
batchStallTime?: number;
batchMaxSize?: number;
batchMaxCount?: number;
Expand Down Expand Up @@ -463,6 +463,7 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
};

#network: null | Network;
#pendingDetectNetwork: null | Promise<Network>;

#scheduleDrain(): void {
if (this.#drainTimer) { return; }
Expand Down Expand Up @@ -554,6 +555,7 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
this.#drainTimer = null;

this.#network = null;
this.#pendingDetectNetwork = null;

{
let resolve: null | ((value: void) => void) = null;
Expand All @@ -563,9 +565,15 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
this.#notReady = { promise, resolve };
}

// Make sure any static network is compatbile with the provided netwrok
const staticNetwork = this._getOption("staticNetwork");
if (staticNetwork) {
if (typeof(staticNetwork) === "boolean") {
assertArgument(!staticNetwork || network !== "any", "staticNetwork cannot be used on special network 'any'", "options", options);
if (staticNetwork && network != null) {
this.#network = Network.from(network);
}

} else if (staticNetwork) {
// Make sure any static network is compatbile with the provided netwrok
assertArgument(network == null || staticNetwork.matches(network),
"staticNetwork MUST match network object", "options", options);
this.#network = staticNetwork;
Expand Down Expand Up @@ -641,36 +649,56 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
*/
async _detectNetwork(): Promise<Network> {
const network = this._getOption("staticNetwork");
if (network) { return network; }
if (network) {
if (network === true) {
if (this.#network) { return this.#network; }
} else {
return network;
}
}

if (this.#pendingDetectNetwork) {
return await this.#pendingDetectNetwork;
}

// If we are ready, use ``send``, which enabled requests to be batched
if (this.ready) {
return Network.from(getBigInt(await this.send("eth_chainId", [ ])));
this.#pendingDetectNetwork = (async () => {
const result = Network.from(getBigInt(await this.send("eth_chainId", [ ])));
this.#pendingDetectNetwork = null;
return result;
})();
return await this.#pendingDetectNetwork;
}

// We are not ready yet; use the primitive _send
this.#pendingDetectNetwork = (async () => {
const payload: JsonRpcPayload = {
id: this.#nextId++, method: "eth_chainId", params: [ ], jsonrpc: "2.0"
};

const payload: JsonRpcPayload = {
id: this.#nextId++, method: "eth_chainId", params: [ ], jsonrpc: "2.0"
};
this.emit("debug", { action: "sendRpcPayload", payload });

this.emit("debug", { action: "sendRpcPayload", payload });
let result: JsonRpcResult | JsonRpcError;
try {
result = (await this._send(payload))[0];
this.#pendingDetectNetwork = null;
} catch (error) {
this.#pendingDetectNetwork = null;
this.emit("debug", { action: "receiveRpcError", error });
throw error;
}

let result: JsonRpcResult | JsonRpcError;
try {
result = (await this._send(payload))[0];
} catch (error) {
this.emit("debug", { action: "receiveRpcError", error });
throw error;
}
this.emit("debug", { action: "receiveRpcResult", result });

this.emit("debug", { action: "receiveRpcResult", result });
if ("result" in result) {
return Network.from(getBigInt(result.result));
}

if ("result" in result) {
return Network.from(getBigInt(result.result));
}
throw this.getRpcError(payload, result);
})();

throw this.getRpcError(payload, result);
return await this.#pendingDetectNetwork;
}

/**
Expand Down
23 changes: 20 additions & 3 deletions src.ts/providers/provider-socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import { JsonRpcApiProvider } from "./provider-jsonrpc.js";

import type { Subscriber, Subscription } from "./abstract-provider.js";
import type { EventFilter } from "./provider.js";
import type { JsonRpcError, JsonRpcPayload, JsonRpcResult } from "./provider-jsonrpc.js";
import type {
JsonRpcApiProviderOptions, JsonRpcError, JsonRpcPayload, JsonRpcResult
} from "./provider-jsonrpc.js";
import type { Networkish } from "./network.js";


Expand Down Expand Up @@ -194,8 +196,23 @@ export class SocketProvider extends JsonRpcApiProvider {
*
* If unspecified, the network will be discovered.
*/
constructor(network?: Networkish) {
super(network, { batchMaxCount: 1 });
constructor(network?: Networkish, _options?: JsonRpcApiProviderOptions) {
// Copy the options
const options = Object.assign({ }, (_options != null) ? _options: { });

// Support for batches is generally not supported for
// connection-base providers; if this changes in the future
// the _send should be updated to reflect this
assertArgument(options.batchMaxCount == null || options.batchMaxCount === 1,
"sockets-based providers do not support batches", "options.batchMaxCount", _options);
options.batchMaxCount = 1;

// Socket-based Providers (generally) cannot change their network,
// since they have a long-lived connection; but let people override
// this if they have just cause.
if (options.staticNetwork == null) { options.staticNetwork = true; }

super(network, options);
this.#callbacks = new Map();
this.#subs = new Map();
this.#pending = new Map();
Expand Down
5 changes: 3 additions & 2 deletions src.ts/providers/provider-websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WebSocket as _WebSocket } from "./ws.js"; /*-browser*/

import { SocketProvider } from "./provider-socket.js";

import type { JsonRpcApiProviderOptions} from "./provider-jsonrpc.js";
import type { Networkish } from "./network.js";

/**
Expand Down Expand Up @@ -45,8 +46,8 @@ export class WebSocketProvider extends SocketProvider {
return this.#websocket;
}

constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish) {
super(network);
constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(network, options);
if (typeof(url) === "string") {
this.#connect = () => { return new _WebSocket(url); };
this.#websocket = this.#connect();
Expand Down

0 comments on commit e777964

Please sign in to comment.