Skip to content

Commit

Permalink
Added customizable quorum to FallbackProvider (#4160).
Browse files Browse the repository at this point in the history
  • Loading branch information
ricmoo committed Jul 27, 2023
1 parent 229145d commit 8f0a509
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
24 changes: 23 additions & 1 deletion src.ts/providers/default-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { QuickNodeProvider } from "./provider-quicknode.js";

import { FallbackProvider } from "./provider-fallback.js";
import { JsonRpcProvider } from "./provider-jsonrpc.js";
import { Network } from "./network.js";
import { WebSocketProvider } from "./provider-websocket.js";

import type { AbstractProvider } from "./abstract-provider.js";
Expand All @@ -22,6 +23,8 @@ function isWebSocketLike(value: any): value is WebSocketLike {
typeof(value.close) === "function");
}

const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goerli matic-mumbai bnbt".split(" ");

export function getDefaultProvider(network: string | Networkish | WebSocketLike, options?: any): AbstractProvider {
if (options == null) { options = { }; }

Expand All @@ -33,6 +36,13 @@ export function getDefaultProvider(network: string | Networkish | WebSocketLike,
return new WebSocketProvider(network);
}

// Get the network name, if possible
let name: null | string = null;
try {
name = Network.from(network).name;
} catch (error) { }


const providers: Array<AbstractProvider> = [ ];

if (options.alchemy !== "-") {
Expand Down Expand Up @@ -96,7 +106,19 @@ export function getDefaultProvider(network: string | Networkish | WebSocketLike,
operation: "getDefaultProvider"
});

// No need for a FallbackProvider
if (providers.length === 1) { return providers[0]; }

return new FallbackProvider(providers);
// We use the floor because public third-party providers can be unreliable,
// so a low number of providers with a large quorum will fail too often
let quorum = Math.floor(providers.length / 2);

// Testnets don't need as strong a security gaurantee and speed is
// more useful during testing
if (name && Testnets.indexOf(name) !== -1) { quorum = 1; }

// Provided override qorum takes priority
if (options && options.quorum) { quorum = options.quorum; }

return new FallbackProvider(providers, undefined, { quorum });
}
29 changes: 21 additions & 8 deletions src.ts/providers/provider-fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,20 @@ async function waitForSync(config: Config, blockNumber: number): Promise<void> {
export type FallbackProviderOptions = {
// How many providers must agree on a value before reporting
// back the response
quorum: number;
quorum?: number;

// How many providers must have reported the same event
// for it to be emitted
eventQuorum: number;
// for it to be emitted (currently unimplmented)
eventQuorum?: number;

// How many providers to dispatch each event to simultaneously.
// Set this to 0 to use getLog polling, which implies eventQuorum
// is equal to quorum.
eventWorkers: number;
// is equal to quorum. (currently unimplemented)
eventWorkers?: number;

cacheTimeout?: number;

pollingInterval?: number;
};

type RunnerResult = { result: any } | { error: Error };
Expand Down Expand Up @@ -380,8 +384,9 @@ export class FallbackProvider extends AbstractProvider {
* If a [[Provider]] is included in %%providers%%, defaults are used
* for the configuration.
*/
constructor(providers: Array<AbstractProvider | FallbackProviderConfig>, network?: Networkish) {
super(network);
constructor(providers: Array<AbstractProvider | FallbackProviderConfig>, network?: Networkish, options?: FallbackProviderOptions) {
super(network, options);

this.#configs = providers.map((p) => {
if (p instanceof AbstractProvider) {
return Object.assign({ provider: p }, defaultConfig, defaultState );
Expand All @@ -393,7 +398,15 @@ export class FallbackProvider extends AbstractProvider {
this.#height = -2;
this.#initialSyncPromise = null;

this.quorum = 2; //Math.ceil(providers.length / 2);
if (options && options.quorum != null) {
this.quorum = options.quorum;
} else {
this.quorum = Math.ceil(this.#configs.reduce((accum, config) => {
accum += config.weight;
return accum;
}, 0) / 2);
}

this.eventQuorum = 1;
this.eventWorkers = 1;

Expand Down

0 comments on commit 8f0a509

Please sign in to comment.