From 22fa5a57a588c3c5c2a72ec5ef539797c2847688 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 6 Apr 2018 15:46:27 +0900 Subject: Refactor RedundantRpcSubprovider into RedundantSubprovider --- packages/subproviders/CHANGELOG.json | 10 ++++ packages/subproviders/src/index.ts | 2 +- .../subproviders/src/subproviders/redundant_rpc.ts | 70 ---------------------- .../src/subproviders/redundant_subprovider.ts | 65 ++++++++++++++++++++ .../test/unit/redundant_rpc_subprovider_test.ts | 17 +++--- packages/website/ts/blockchain.ts | 25 ++++++-- 6 files changed, 104 insertions(+), 85 deletions(-) delete mode 100644 packages/subproviders/src/subproviders/redundant_rpc.ts create mode 100644 packages/subproviders/src/subproviders/redundant_subprovider.ts (limited to 'packages') diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index 54eb32378..ca3889202 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,4 +1,14 @@ [ + { + "version": "0.9.0", + "changes": [ + { + "note": + "Refactor RedundantRPCSubprovider into RedundantSubprovider where it now accepts an array of subproviders rather then an array of RPC endpoints", + "pr": 500 + } + ] + }, { "timestamp": 1522673609, "version": "0.8.4", diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 9786347e6..1711387f1 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -7,7 +7,7 @@ import { LedgerEthereumClient } from './types'; export { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider'; export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider'; export { InjectedWeb3Subprovider } from './subproviders/injected_web3'; -export { RedundantRPCSubprovider } from './subproviders/redundant_rpc'; +export { RedundantSubprovider } from './subproviders/redundant_subprovider'; export { LedgerSubprovider } from './subproviders/ledger'; export { GanacheSubprovider } from './subproviders/ganache'; export { Subprovider } from './subproviders/subprovider'; diff --git a/packages/subproviders/src/subproviders/redundant_rpc.ts b/packages/subproviders/src/subproviders/redundant_rpc.ts deleted file mode 100644 index f8ff0915d..000000000 --- a/packages/subproviders/src/subproviders/redundant_rpc.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { JSONRPCRequestPayload } from '@0xproject/types'; -import { promisify } from '@0xproject/utils'; -import * as _ from 'lodash'; -import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); - -import { Callback } from '../types'; - -import { Subprovider } from './subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * It attempts to handle each JSON RPC request by sequentially attempting to receive a valid response from one of a - * set of JSON RPC endpoints. - */ -export class RedundantRPCSubprovider extends Subprovider { - private _rpcs: RpcSubprovider[]; - private static async _firstSuccessAsync( - rpcs: RpcSubprovider[], - payload: JSONRPCRequestPayload, - next: Callback, - ): Promise { - let lastErr: Error | undefined; - for (const rpc of rpcs) { - try { - const data = await promisify(rpc.handleRequest.bind(rpc))(payload, next); - return data; - } catch (err) { - lastErr = err; - continue; - } - } - if (!_.isUndefined(lastErr)) { - throw lastErr; - } - } - /** - * Instantiates a new RedundantRPCSubprovider - * @param endpoints JSON RPC endpoints to attempt. Attempts are made in the order of the endpoints. - */ - constructor(endpoints: string[]) { - super(); - this._rpcs = _.map(endpoints, endpoint => { - return new RpcSubprovider({ - rpcUrl: endpoint, - }); - }); - } - /** - * This method conforms to the web3-provider-engine interface. - * It is called internally by the ProviderEngine when it is this subproviders - * turn to handle a JSON RPC request. - * @param payload JSON RPC payload - * @param next Callback to call if this subprovider decides not to handle the request - * @param end Callback to call if subprovider handled the request and wants to pass back the request. - */ - // tslint:disable-next-line:async-suffix - public async handleRequest( - payload: JSONRPCRequestPayload, - next: Callback, - end: (err: Error | null, data?: any) => void, - ): Promise { - const rpcsCopy = this._rpcs.slice(); - try { - const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next); - end(null, data); - } catch (err) { - end(err); - } - } -} diff --git a/packages/subproviders/src/subproviders/redundant_subprovider.ts b/packages/subproviders/src/subproviders/redundant_subprovider.ts new file mode 100644 index 000000000..37c8bba5a --- /dev/null +++ b/packages/subproviders/src/subproviders/redundant_subprovider.ts @@ -0,0 +1,65 @@ +import { JSONRPCRequestPayload } from '@0xproject/types'; +import { promisify } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { Callback } from '../types'; + +import { Subprovider } from './subprovider'; + +/** + * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. + * It attempts to handle each JSON RPC request by sequentially attempting to receive a valid response from one of a + * set of JSON RPC endpoints. + */ +export class RedundantSubprovider extends Subprovider { + private _subproviders: Subprovider[]; + private static async _firstSuccessAsync( + subproviders: Subprovider[], + payload: JSONRPCRequestPayload, + next: Callback, + ): Promise { + let lastErr: Error | undefined; + for (const subprovider of subproviders) { + try { + const data = await promisify(subprovider.handleRequest.bind(subprovider))(payload, next); + return data; + } catch (err) { + lastErr = err; + continue; + } + } + if (!_.isUndefined(lastErr)) { + throw lastErr; + } + } + /** + * Instantiates a new RedundantSubprovider + * @param endpoints JSON RPC endpoints to attempt. Attempts are made in the order of the endpoints. + */ + constructor(subproviders: Subprovider[]) { + super(); + this._subproviders = subproviders; + } + /** + * This method conforms to the web3-provider-engine interface. + * It is called internally by the ProviderEngine when it is this subproviders + * turn to handle a JSON RPC request. + * @param payload JSON RPC payload + * @param next Callback to call if this subprovider decides not to handle the request + * @param end Callback to call if subprovider handled the request and wants to pass back the request. + */ + // tslint:disable-next-line:async-suffix + public async handleRequest( + payload: JSONRPCRequestPayload, + next: Callback, + end: (err: Error | null, data?: any) => void, + ): Promise { + const subprovidersCopy = this._subproviders.slice(); + try { + const data = await RedundantSubprovider._firstSuccessAsync(subprovidersCopy, payload, next); + end(null, data); + } catch (err) { + end(err); + } + } +} diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts index e7ca6d496..e25cb7eb7 100644 --- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts +++ b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts @@ -5,7 +5,8 @@ import Web3 = require('web3'); import Web3ProviderEngine = require('web3-provider-engine'); import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); -import { RedundantRPCSubprovider } from '../../src'; +import { RedundantSubprovider } from '../../src'; +import { Subprovider } from '../../src/subproviders/subprovider'; import { DoneCallback } from '../../src/types'; import { chaiSetup } from '../chai_setup'; import { ganacheSubprovider } from '../utils/ganache_subprovider'; @@ -14,14 +15,12 @@ import { reportCallbackErrors } from '../utils/report_callback_errors'; const expect = chai.expect; chaiSetup.configure(); -describe('RedundantRpcSubprovider', () => { +describe('RedundantSubprovider', () => { let provider: Web3ProviderEngine; it('succeeds when supplied a healthy endpoint', (done: DoneCallback) => { provider = new Web3ProviderEngine(); - const endpoints = ['http://localhost:8545']; - const redundantSubprovider = new RedundantRPCSubprovider(endpoints); - // Hack: Hot-swap rpc with ganacheSubprovider - (redundantSubprovider as any)._rpcs = [ganacheSubprovider]; + const subproviders = [ganacheSubprovider]; + const redundantSubprovider = new RedundantSubprovider(subproviders); provider.addProvider(redundantSubprovider); provider.start(); @@ -40,13 +39,11 @@ describe('RedundantRpcSubprovider', () => { }); it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => { provider = new Web3ProviderEngine(); - const endpoints = ['http://does-not-exist:3000', 'http://localhost:8545']; - const redundantSubprovider = new RedundantRPCSubprovider(endpoints); - // Hack: Hot-swap rpcs with [nonExistentSubprovider, ganacheSubprovider] const nonExistentSubprovider = new RpcSubprovider({ rpcUrl: 'http://does-not-exist:3000', }); - (redundantSubprovider as any)._rpcs = [nonExistentSubprovider, ganacheSubprovider]; + const subproviders = [nonExistentSubprovider as Subprovider, ganacheSubprovider]; + const redundantSubprovider = new RedundantSubprovider(subproviders); provider.addProvider(redundantSubprovider); provider.start(); diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index fd34ab82d..7d79542a3 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -21,7 +21,8 @@ import { ledgerEthereumBrowserClientFactoryAsync, LedgerSubprovider, LedgerWalletSubprovider, - RedundantRPCSubprovider, + RedundantSubprovider, + Subprovider, } from '@0xproject/subproviders'; import { Provider } from '@0xproject/types'; import { BigNumber, intervalUtils, logUtils, promisify } from '@0xproject/utils'; @@ -54,6 +55,7 @@ import { utils } from 'ts/utils/utils'; import Web3 = require('web3'); import ProviderEngine = require('web3-provider-engine'); import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); +import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import * as MintableArtifacts from '../contracts/Mintable.json'; @@ -98,7 +100,12 @@ export class Blockchain { provider = new ProviderEngine(); provider.addProvider(new InjectedWeb3Subprovider(injectedWeb3.currentProvider)); provider.addProvider(new FilterSubprovider()); - provider.addProvider(new RedundantRPCSubprovider(publicNodeUrlsIfExistsForNetworkId)); + const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => { + return new RpcSubprovider({ + rpcUrl: publicNodeUrl, + }); + }); + provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); } else if (doesInjectedWeb3Exist) { // Since no public node for this network, all requests go to injectedWeb3 instance @@ -110,7 +117,12 @@ export class Blockchain { provider = new ProviderEngine(); provider.addProvider(new FilterSubprovider()); const networkId = configs.IS_MAINNET_ENABLED ? constants.NETWORK_ID_MAINNET : constants.NETWORK_ID_KOVAN; - provider.addProvider(new RedundantRPCSubprovider(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId])); + const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => { + return new RpcSubprovider({ + rpcUrl: publicNodeUrl, + }); + }); + provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); } @@ -201,7 +213,12 @@ export class Blockchain { this._ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs); provider.addProvider(this._ledgerSubprovider); provider.addProvider(new FilterSubprovider()); - provider.addProvider(new RedundantRPCSubprovider(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId])); + const rpcSubproviders = _.map(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], publicNodeUrl => { + return new RpcSubprovider({ + rpcUrl: publicNodeUrl, + }); + }); + provider.addProvider(new RedundantSubprovider(rpcSubproviders as Subprovider[])); provider.start(); this.networkId = networkId; this._dispatcher.updateNetworkId(this.networkId); -- cgit