Add auto-detected static network support to providers and allow customizing socket provider options (#4199, #4418, #4441).
This commit is contained in:
parent
9e74d14432
commit
4681b83d51
@ -3,6 +3,8 @@ import { connect } from "net";
|
|||||||
import { SocketProvider } from "./provider-socket.js";
|
import { SocketProvider } from "./provider-socket.js";
|
||||||
|
|
||||||
import type { Socket } from "net";
|
import type { Socket } from "net";
|
||||||
|
|
||||||
|
import type { JsonRpcApiProviderOptions } from "./provider-jsonrpc.js";
|
||||||
import type { Networkish } from "./network.js";
|
import type { Networkish } from "./network.js";
|
||||||
|
|
||||||
|
|
||||||
@ -35,8 +37,8 @@ export class IpcSocketProvider extends SocketProvider {
|
|||||||
*/
|
*/
|
||||||
get socket(): Socket { return this.#socket; }
|
get socket(): Socket { return this.#socket; }
|
||||||
|
|
||||||
constructor(path: string, network?: Networkish) {
|
constructor(path: string, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||||
super(network);
|
super(network, options);
|
||||||
this.#socket = connect(path);
|
this.#socket = connect(path);
|
||||||
|
|
||||||
this.socket.on("ready", async () => {
|
this.socket.on("ready", async () => {
|
||||||
|
@ -190,7 +190,7 @@ export type DebugEventJsonRpcApiProvider = {
|
|||||||
*/
|
*/
|
||||||
export type JsonRpcApiProviderOptions = {
|
export type JsonRpcApiProviderOptions = {
|
||||||
polling?: boolean;
|
polling?: boolean;
|
||||||
staticNetwork?: null | Network;
|
staticNetwork?: null | boolean | Network;
|
||||||
batchStallTime?: number;
|
batchStallTime?: number;
|
||||||
batchMaxSize?: number;
|
batchMaxSize?: number;
|
||||||
batchMaxCount?: number;
|
batchMaxCount?: number;
|
||||||
@ -463,6 +463,7 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#network: null | Network;
|
#network: null | Network;
|
||||||
|
#pendingDetectNetwork: null | Promise<Network>;
|
||||||
|
|
||||||
#scheduleDrain(): void {
|
#scheduleDrain(): void {
|
||||||
if (this.#drainTimer) { return; }
|
if (this.#drainTimer) { return; }
|
||||||
@ -554,6 +555,7 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
this.#drainTimer = null;
|
this.#drainTimer = null;
|
||||||
|
|
||||||
this.#network = null;
|
this.#network = null;
|
||||||
|
this.#pendingDetectNetwork = null;
|
||||||
|
|
||||||
{
|
{
|
||||||
let resolve: null | ((value: void) => void) = null;
|
let resolve: null | ((value: void) => void) = null;
|
||||||
@ -563,9 +565,15 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
this.#notReady = { promise, resolve };
|
this.#notReady = { promise, resolve };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure any static network is compatbile with the provided netwrok
|
|
||||||
const staticNetwork = this._getOption("staticNetwork");
|
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),
|
assertArgument(network == null || staticNetwork.matches(network),
|
||||||
"staticNetwork MUST match network object", "options", options);
|
"staticNetwork MUST match network object", "options", options);
|
||||||
this.#network = staticNetwork;
|
this.#network = staticNetwork;
|
||||||
@ -641,36 +649,56 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
*/
|
*/
|
||||||
async _detectNetwork(): Promise<Network> {
|
async _detectNetwork(): Promise<Network> {
|
||||||
const network = this._getOption("staticNetwork");
|
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 we are ready, use ``send``, which enabled requests to be batched
|
||||||
if (this.ready) {
|
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
|
// 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 = {
|
this.emit("debug", { action: "sendRpcPayload", payload });
|
||||||
id: this.#nextId++, method: "eth_chainId", params: [ ], jsonrpc: "2.0"
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
this.emit("debug", { action: "receiveRpcResult", result });
|
||||||
try {
|
|
||||||
result = (await this._send(payload))[0];
|
|
||||||
} catch (error) {
|
|
||||||
this.emit("debug", { action: "receiveRpcError", error });
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("debug", { action: "receiveRpcResult", result });
|
if ("result" in result) {
|
||||||
|
return Network.from(getBigInt(result.result));
|
||||||
|
}
|
||||||
|
|
||||||
if ("result" in result) {
|
throw this.getRpcError(payload, result);
|
||||||
return Network.from(getBigInt(result.result));
|
})();
|
||||||
}
|
|
||||||
|
|
||||||
throw this.getRpcError(payload, result);
|
return await this.#pendingDetectNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,9 @@ import { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
|||||||
|
|
||||||
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
||||||
import type { EventFilter } from "./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";
|
import type { Networkish } from "./network.js";
|
||||||
|
|
||||||
|
|
||||||
@ -194,8 +196,23 @@ export class SocketProvider extends JsonRpcApiProvider {
|
|||||||
*
|
*
|
||||||
* If unspecified, the network will be discovered.
|
* If unspecified, the network will be discovered.
|
||||||
*/
|
*/
|
||||||
constructor(network?: Networkish) {
|
constructor(network?: Networkish, _options?: JsonRpcApiProviderOptions) {
|
||||||
super(network, { batchMaxCount: 1 });
|
// 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.#callbacks = new Map();
|
||||||
this.#subs = new Map();
|
this.#subs = new Map();
|
||||||
this.#pending = new Map();
|
this.#pending = new Map();
|
||||||
|
@ -4,6 +4,7 @@ import { WebSocket as _WebSocket } from "./ws.js"; /*-browser*/
|
|||||||
|
|
||||||
import { SocketProvider } from "./provider-socket.js";
|
import { SocketProvider } from "./provider-socket.js";
|
||||||
|
|
||||||
|
import type { JsonRpcApiProviderOptions} from "./provider-jsonrpc.js";
|
||||||
import type { Networkish } from "./network.js";
|
import type { Networkish } from "./network.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,8 +46,8 @@ export class WebSocketProvider extends SocketProvider {
|
|||||||
return this.#websocket;
|
return this.#websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish) {
|
constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||||
super(network);
|
super(network, options);
|
||||||
if (typeof(url) === "string") {
|
if (typeof(url) === "string") {
|
||||||
this.#connect = () => { return new _WebSocket(url); };
|
this.#connect = () => { return new _WebSocket(url); };
|
||||||
this.#websocket = this.#connect();
|
this.#websocket = this.#connect();
|
||||||
|
Loading…
Reference in New Issue
Block a user