Skip to content

Commit

Permalink
Added CommunityResourcable to mark Providers as highly throttled.
Browse files Browse the repository at this point in the history
  • Loading branch information
ricmoo committed Oct 7, 2020
1 parent 50f84b3 commit a022093
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 16 deletions.
26 changes: 22 additions & 4 deletions packages/providers/src.ts/alchemy-provider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"use strict";

import { Network, Networkish } from "@ethersproject/networks";
import { defineReadOnly } from "@ethersproject/properties";
import { ConnectionInfo } from "@ethersproject/web";

import { showThrottleMessage } from "./formatter";
import { CommunityResourcable, showThrottleMessage } from "./formatter";
import { WebSocketProvider } from "./websocket-provider";

import { Logger } from "@ethersproject/logger";
Expand All @@ -19,15 +20,28 @@ import { UrlJsonRpcProvider } from "./url-json-rpc-provider";

const defaultApiKey = "_gg7wSSi0KMBsdKnGVfHDueq6xMB9EkC"

export class AlchemyProvider extends UrlJsonRpcProvider {
export class AlchemyWebSocketProvider extends WebSocketProvider implements CommunityResourcable {
readonly apiKey: string;

static getWebSocketProvider(network?: Networkish, apiKey?: any): WebSocketProvider {
constructor(network?: Networkish, apiKey?: any) {
const provider = new AlchemyProvider(network, apiKey);

const url = provider.connection.url.replace(/^http/i, "ws")
.replace(".alchemyapi.", ".ws.alchemyapi.");

return new WebSocketProvider(url, provider.network);
super(url, provider.network);
defineReadOnly(this, "apiKey", provider.apiKey);
}

isCommunityResource(): boolean {
return (this.apiKey === defaultApiKey);
}
}

export class AlchemyProvider extends UrlJsonRpcProvider {

static getWebSocketProvider(network?: Networkish, apiKey?: any): AlchemyWebSocketProvider {
return new AlchemyWebSocketProvider(network, apiKey);
}

static getApiKey(apiKey: any): any {
Expand Down Expand Up @@ -70,4 +84,8 @@ export class AlchemyProvider extends UrlJsonRpcProvider {
}
};
}

isCommunityResource(): boolean {
return (this.apiKey === defaultApiKey);
}
}
6 changes: 5 additions & 1 deletion packages/providers/src.ts/etherscan-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export class EtherscanProvider extends BaseProvider{
url: url,
throttleSlotInterval: 1000,
throttleCallback: (attempt: number, url: string) => {
if (this.apiKey === defaultApiKey) {
if (this.isCommunityResource()) {
showThrottleMessage();
}
return Promise.resolve(true);
Expand Down Expand Up @@ -424,4 +424,8 @@ export class EtherscanProvider extends BaseProvider{
});
});
}

isCommunityResource(): boolean {
return (this.apiKey === defaultApiKey);
}
}
9 changes: 7 additions & 2 deletions packages/providers/src.ts/fallback-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { shuffled } from "@ethersproject/random";
import { poll } from "@ethersproject/web";

import { BaseProvider } from "./base-provider";
import { isCommunityResource } from "./formatter";

import { Logger } from "@ethersproject/logger";
import { version } from "./_version";
Expand Down Expand Up @@ -417,13 +418,17 @@ export class FallbackProvider extends BaseProvider {

const providerConfigs: Array<FallbackProviderConfig> = providers.map((configOrProvider, index) => {
if (Provider.isProvider(configOrProvider)) {
return Object.freeze({ provider: configOrProvider, weight: 1, stallTimeout: 750, priority: 1 });
const stallTimeout = isCommunityResource(configOrProvider) ? 2000: 750;
const priority = 1;
return Object.freeze({ provider: configOrProvider, weight: 1, stallTimeout, priority });
}

const config: FallbackProviderConfig = shallowCopy(configOrProvider);

if (config.priority == null) { config.priority = 1; }
if (config.stallTimeout == null) { config.stallTimeout = 750; }
if (config.stallTimeout == null) {
config.stallTimeout = isCommunityResource(configOrProvider) ? 2000: 750;
}
if (config.weight == null) { config.weight = 1; }

const weight = config.weight;
Expand Down
12 changes: 12 additions & 0 deletions packages/providers/src.ts/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ export class Formatter {
}
}

export interface CommunityResourcable {
isCommunityResource(): boolean;
}

export function isCommunityResourcable(value: any): value is CommunityResourcable {
return (value && typeof(value.isCommunityResource) === "function");
}

export function isCommunityResource(value: any): boolean {
return (isCommunityResourcable(value) && value.isCommunityResource());
}

// Show the throttle message only once
let throttleMessage = false;
export function showThrottleMessage() {
Expand Down
15 changes: 11 additions & 4 deletions packages/providers/src.ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ import { Network, Networkish } from "@ethersproject/networks";

import { BaseProvider, EnsProvider, EnsResolver, Resolver } from "./base-provider";

import { AlchemyProvider } from "./alchemy-provider";
import { AlchemyProvider, AlchemyWebSocketProvider } from "./alchemy-provider";
import { CloudflareProvider } from "./cloudflare-provider";
import { EtherscanProvider } from "./etherscan-provider";
import { FallbackProvider } from "./fallback-provider";
import { IpcProvider } from "./ipc-provider";
import { InfuraProvider } from "./infura-provider";
import { InfuraProvider, InfuraWebSocketProvider } from "./infura-provider";
import { JsonRpcProvider, JsonRpcSigner } from "./json-rpc-provider";
import { NodesmithProvider } from "./nodesmith-provider";
import { StaticJsonRpcProvider, UrlJsonRpcProvider } from "./url-json-rpc-provider";
import { Web3Provider } from "./web3-provider";
import { WebSocketProvider } from "./websocket-provider";
import { ExternalProvider, JsonRpcFetchFunc } from "./web3-provider";

import { Formatter } from "./formatter";
import { CommunityResourcable, Formatter, isCommunityResourcable, isCommunityResource, showThrottleMessage } from "./formatter";

import { Logger } from "@ethersproject/logger";
import { version } from "./_version";
Expand Down Expand Up @@ -103,9 +103,11 @@ export {
FallbackProvider,

AlchemyProvider,
AlchemyWebSocketProvider,
CloudflareProvider,
EtherscanProvider,
InfuraProvider,
InfuraWebSocketProvider,
JsonRpcProvider,
NodesmithProvider,
StaticJsonRpcProvider,
Expand All @@ -126,6 +128,9 @@ export {

getDefaultProvider,
getNetwork,
isCommunityResource,
isCommunityResourcable,
showThrottleMessage,


///////////////////////
Expand Down Expand Up @@ -154,6 +159,8 @@ export {
Networkish,

EnsProvider,
EnsResolver
EnsResolver,

CommunityResourcable
};

31 changes: 27 additions & 4 deletions packages/providers/src.ts/infura-provider.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"use strict";

import { Network, Networkish } from "@ethersproject/networks";
import { defineReadOnly } from "@ethersproject/properties";
import { ConnectionInfo } from "@ethersproject/web";

import { WebSocketProvider } from "./websocket-provider";
import { showThrottleMessage } from "./formatter";
import { CommunityResourcable, showThrottleMessage } from "./formatter";

import { Logger } from "@ethersproject/logger";
import { version } from "./_version";
Expand All @@ -15,11 +16,12 @@ import { UrlJsonRpcProvider } from "./url-json-rpc-provider";

const defaultProjectId = "84842078b09946638c03157f83405213"

export class InfuraProvider extends UrlJsonRpcProvider {
export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable {
readonly apiKey: string;
readonly projectId: string;
readonly projectSecret: string;

static getWebSocketProvider(network?: Networkish, apiKey?: any): WebSocketProvider {
constructor(network?: Networkish, apiKey?: any) {
const provider = new InfuraProvider(network, apiKey);
const connection = provider.connection;
if (connection.password) {
Expand All @@ -29,7 +31,24 @@ export class InfuraProvider extends UrlJsonRpcProvider {
}

const url = connection.url.replace(/^http/i, "ws").replace("/v3/", "/ws/v3/");
return new WebSocketProvider(url, network);
super(url, network);

defineReadOnly(this, "apiKey", provider.projectId);
defineReadOnly(this, "projectId", provider.projectId);
defineReadOnly(this, "projectSecret", provider.projectSecret);
}

isCommunityResource(): boolean {
return (this.projectId === defaultProjectId);
}
}

export class InfuraProvider extends UrlJsonRpcProvider {
readonly projectId: string;
readonly projectSecret: string;

static getWebSocketProvider(network?: Networkish, apiKey?: any): InfuraWebSocketProvider {
return new InfuraWebSocketProvider(network, apiKey);
}

static getApiKey(apiKey: any): any {
Expand Down Expand Up @@ -104,4 +123,8 @@ export class InfuraProvider extends UrlJsonRpcProvider {

return connection;
}

isCommunityResource(): boolean {
return (this.projectId === defaultProjectId);
}
}
7 changes: 6 additions & 1 deletion packages/providers/src.ts/url-json-rpc-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Logger } from "@ethersproject/logger";
import { version } from "./_version";
const logger = new Logger(version);

import { CommunityResourcable } from "./formatter";
import { JsonRpcProvider, JsonRpcSigner } from "./json-rpc-provider";

type getUrlFunc = (network: Network, apiKey: string) => string | ConnectionInfo;
Expand Down Expand Up @@ -46,7 +47,7 @@ export class StaticJsonRpcProvider extends JsonRpcProvider {
}
}

export abstract class UrlJsonRpcProvider extends StaticJsonRpcProvider {
export abstract class UrlJsonRpcProvider extends StaticJsonRpcProvider implements CommunityResourcable {
readonly apiKey: any;

constructor(network?: Networkish, apiKey?: any) {
Expand All @@ -73,6 +74,10 @@ export abstract class UrlJsonRpcProvider extends StaticJsonRpcProvider {
logger.warn("WARNING: API provider does not support pending filters");
}

isCommunityResource(): boolean {
return false;
}

getSigner(address?: string): JsonRpcSigner {
return logger.throwError(
"API provider does not support signing",
Expand Down

0 comments on commit a022093

Please sign in to comment.