Attempting to fix tests

Tests are not working currently, however given the current changes, the non-test functionality of the proxy is still working correctly.
This commit is contained in:
emizzle 2019-11-14 18:35:12 +11:00
parent b5aa508992
commit 9239c91492
No known key found for this signature in database
GPG Key ID: 1FD4BAB3C37EE9BA
8 changed files with 140 additions and 86 deletions

View File

@ -52,6 +52,7 @@ export interface Config {
rpcCorsDomain: string;
wsRPC: boolean;
isDev: boolean;
client: string;
};
webServerConfig: {
certOptions: {

View File

@ -1,6 +1,6 @@
class Ganache {
constructor(embark) {
embark.events.request('proxy:vm:register', () => {
embark.events.request('blockchain:vm:register', () => {
const ganache = require('ganache-cli');
return ganache.provider();
});

View File

@ -12,7 +12,7 @@ export default class EthSubscribe extends RpcModifier {
private async ethSubscribeRequest(params: any, callback: Callback<any>) {
// check for eth_subscribe and websockets
if (params.isWs && params.request.method.includes("eth_subscribe")) {
if (params.isWs && params.request.method === "eth_subscribe") {
// indicate that we do not want this call to go to the node
params.sendToNode = false;
return callback(null, params);

View File

@ -1,12 +1,9 @@
import { Callback, Embark, Events } /* supplied by @types/embark in packages/embark-typings */ from "embark";
import Web3RequestManager from "web3-core-requestmanager";
import { __ } from "embark-i18n";
import Web3 from "web3";
import RpcModifier from "./rpcModifier";
export default class EthUnsubscribe extends RpcModifier {
private nodeSubscriptions: object = {};
constructor(embark: Embark, rpcModifierEvents: Events) {
super(embark, rpcModifierEvents);
@ -16,7 +13,7 @@ export default class EthUnsubscribe extends RpcModifier {
private async ethUnsubscribeRequest(params: any, callback: Callback<any>) {
// check for eth_subscribe and websockets
if (params.isWs && params.request.method.includes("eth_unsubscribe")) {
if (params.isWs && params.request.method === "eth_unsubscribe") {
// indicate that we do not want this call to go to the node
params.sendToNode = false;
return callback(null, params);

View File

@ -9,30 +9,42 @@ class BlockchainClient {
this.blockchainClients = {};
this.client = null;
this.vms = [];
this.events.setCommandHandler("blockchain:client:register", (clientName, blockchainClient) => {
this.blockchainClients[clientName] = blockchainClient;
this.client = blockchainClient;
});
this.events.setCommandHandler("blockchain:vm:register", (handler) => {
this.vms.push(handler);
});
// TODO: unclear currently if this belongs here so it's a bit hardcoded for now
this.events.setCommandHandler("blockchain:client:provider", (clientName, cb) => {
this.events.request("proxy:endpoint:get", (err, endpoint) => {
if (err) {
return cb(err);
}
if (endpoint.startsWith('ws')) {
return cb(null, new Web3.providers.WebsocketProvider(endpoint, {
headers: {Origin: constants.embarkResourceOrigin},
// TODO remove this when Geth fixes this: https://github.com/ethereum/go-ethereum/issues/16846
// Edit: This has been fixed in Geth 1.9, but we don't support 1.9 yet and still support 1.8
clientConfig: {
fragmentationThreshold: 81920
}
}));
}
const web3 = new Web3(endpoint);
cb(null, web3.currentProvider);
});
this.events.setCommandHandler("blockchain:client:nodeProvider", async (clientName, endpoint, cb) => {
if (!cb) {
cb = endpoint;
endpoint = null;
}
if (clientName === constants.blockchain.vm) {
return cb(null, this.vms[this.vms.length - 1]());
}
let provider;
try {
provider = await this._getProvider(clientName, endpoint);
}
catch (err) {
return cb(`Error getting provider: ${err.message || err}`);
}
cb(null, provider);
});
this.events.setCommandHandler("blockchain:client:provider", async (clientName, cb) => {
let provider;
try {
provider = await this._getProvider(clientName);
}
catch (err) {
return cb(`Error getting provider: ${err.message || err}`);
}
cb(null, provider);
});
// TODO: maybe not the ideal event to listen to?
@ -46,7 +58,28 @@ class BlockchainClient {
// set default account
});
}
async _getProvider(clientName, endpoint) {
// Passing in an endpoint allows us to customise which URL the provider connects to.
// If no endpoint is providing, the provider will connect to the proxy.
// Explicity setting an endpoint is useful for cases where we want to connect directly
// to the node (ie in the proxy).
if (!endpoint) {
// will return the proxy URL
endpoint = await this.events.request2("proxy:endpoint:get");
}
if (endpoint.startsWith('ws')) {
return new Web3.providers.WebsocketProvider(endpoint, {
headers: { Origin: constants.embarkResourceOrigin },
// TODO remove this when Geth fixes this: https://github.com/ethereum/go-ethereum/issues/16846
// Edit: This has been fixed in Geth 1.9, but we don't support 1.9 yet and still support 1.8
clientConfig: {
fragmentationThreshold: 81920
}
});
}
const web3 = new Web3(endpoint);
return web3.currentProvider;
}
}
module.exports = BlockchainClient;

View File

@ -1,5 +1,5 @@
import {Embark, Events } /* supplied by @types/embark in packages/embark-typings */ from "embark";
import {__} from "embark-i18n";
import { Embark, Events } /* supplied by @types/embark in packages/embark-typings */ from "embark";
import { __ } from "embark-i18n";
import { buildUrl, findNextPort } from "embark-utils";
import { Logger } from 'embark-logger';
import { Proxy } from "./proxy";
@ -18,6 +18,8 @@ export default class ProxyManager {
private ready = false;
private isWs = false;
private vms: any[];
private _endpoint: string = "";
private portsSetup: boolean = false;
constructor(private embark: Embark, options: any) {
this.logger = embark.logger;
@ -50,19 +52,28 @@ export default class ProxyManager {
this.events.setCommandHandler("proxy:endpoint:get", async (cb) => {
await this.onReady();
if (!this.embark.config.blockchainConfig.proxy) {
return cb(null, this.embark.config.blockchainConfig.endpoint);
cb(null, (await this.endpoint));
});
}
private get endpoint() {
return (async () => {
if (this._endpoint) {
return this._endpoint;
}
if (!this.embark.config.blockchainConfig.proxy) {
this._endpoint = this.embark.config.blockchainConfig.endpoint;
return this._endpoint;
}
await this.setupPorts();
// TODO Check if the proxy can support HTTPS, though it probably doesn't matter since it's local
if (this.isWs) {
return cb(null, buildUrl("ws", this.host, this.wsPort, "ws"));
this._endpoint = buildUrl("ws", this.host, this.wsPort, "ws");
return this._endpoint;
}
cb(null, buildUrl("http", this.host, this.rpcPort, "rpc"));
});
this.events.setCommandHandler("proxy:vm:register", (handler: any) => {
this.vms.push(handler);
});
this._endpoint = buildUrl("http", this.host, this.rpcPort, "rpc");
return this._endpoint;
})();
}
public onReady() {
@ -76,50 +87,65 @@ export default class ProxyManager {
});
}
private async setupPorts() {
if (this.portsSetup) {
return;
}
const port = await findNextPort(this.embark.config.blockchainConfig.rpcPort + constants.blockchain.servicePortOnProxy);
this.portsSetup = true;
this.rpcPort = port;
this.wsPort = port + 1;
this.isWs = this.embark.config.blockchainConfig.client === constants.blockchain.vm || (/wss?/).test(this.embark.config.blockchainConfig.endpoint);
}
private async setupProxy(clientName: string) {
await this.setupPorts();
if (!this.embark.config.blockchainConfig.proxy) {
return;
}
if (this.httpProxy || this.wsProxy) {
throw new Error("Proxy is already started");
}
const port = await findNextPort(this.embark.config.blockchainConfig.rpcPort + constants.blockchain.servicePortOnProxy);
this.rpcPort = port;
this.wsPort = port + 1;
this.isWs = clientName === constants.blockchain.vm || (/wss?/).test(this.embark.config.blockchainConfig.endpoint);
const endpoint = this.embark.config.blockchainConfig.endpoint;
let isVm = false;
// using simulator, ie tests
if (clientName === constants.blockchain.vm) {
this.isWs = true;
isVm = true;
}
// HTTP
if (clientName !== constants.blockchain.vm) {
this.httpProxy = await new Proxy({
endpoint: this.embark.config.blockchainConfig.endpoint,
endpoint,
events: this.events,
isWs: false,
logger: this.logger,
plugins: this.plugins,
vms: this.vms,
plugins: this.plugins
})
.serve(
this.host,
this.rpcPort,
);
.serve(
this.host,
this.rpcPort,
);
this.logger.info(`HTTP Proxy for node endpoint ${this.embark.config.blockchainConfig.endpoint} listening on ${buildUrl("http", this.host, this.rpcPort, "rpc")}`);
}
if (this.isWs) {
const endpoint = clientName === constants.blockchain.vm ? constants.blockchain.vm : this.embark.config.blockchainConfig.endpoint;
this.wsProxy = await new Proxy({
endpoint,
events: this.events,
isWs: true,
logger: this.logger,
plugins: this.plugins,
vms: this.vms,
clientName
})
.serve(
this.host,
this.wsPort,
);
this.logger.info(`WS Proxy for node endpoint ${endpoint} listening on ${buildUrl("ws", this.host, this.wsPort, "ws")}`);
.serve(
this.host,
this.wsPort,
);
this.logger.info(`WS Proxy for node endpoint ${isVm ? 'vm' : endpoint} listening on ${buildUrl("ws", this.host, this.wsPort, "ws")}`);
}
}
private stopProxy() {

View File

@ -17,41 +17,35 @@ export class Proxy {
this.timeouts = {};
this.plugins = options.plugins;
this.logger = options.logger;
this.vms = options.vms;
this.app = null;
this.endpoint = options.endpoint;
this.events = options.events;
if (options.endpoint === constants.blockchain.vm) {
this.endpoint = this.vms[this.vms.length - 1]();
}
let provider = null;
if (typeof this.endpoint === 'string' && this.endpoint.startsWith('ws')) {
provider = this._createWebSocketProvider();
} else {
provider = this.endpoint;
}
this.isWs = options.isWs;
// used to service all non-long-living WS connections, including any
// request that is not WS and any WS request that is not an `eth_subscribe`
// RPC request
this.requestManager = this._createWeb3RequestManager(provider);
this.clientName = options.clientName;
this.nodeSubscriptions = {};
this._requestManager = null;
this.events.setCommandHandler("proxy:websocket:subscribe", this.handleSubscribe.bind(this));
this.events.setCommandHandler("proxy:websocket:unsubscribe", this.handleUnsubscribe.bind(this));
}
_createWebSocketProvider() {
return new Web3WsProvider(this.endpoint, {
headers: { Origin: constants.embarkResourceOrigin },
// TODO remove this when Geth fixes this: https://github.com/ethereum/go-ethereum/issues/16846
// Edit: This has been fixed in Geth 1.9, but we don't support 1.9 yet and still support 1.8
clientConfig: {
fragmentationThreshold: 81920
// used to service all non-long-living WS connections, including any
// request that is not WS and any WS request that is not an `eth_subscribe`
// RPC request
get requestManager() {
return (async () => {
if (!this._requestManager) {
const provider = await this._createWebSocketProvider(this.endpoint);
this._requestManager = this._createWeb3RequestManager(provider);
}
});
return this._requestManager;
})();
}
async _createWebSocketProvider(endpoint) {
// pass in endpoint to ensure we get a provider with a connection to the node
// this may return a VM provider during tests, in which case endpoint will be ignored
return this.events.request2("blockchain:client:nodeProvider", this.clientName /* TODO: test that this returns "vm" or "ethereum" */, endpoint);
}
_createWeb3RequestManager(provider) {
@ -60,7 +54,8 @@ export class Proxy {
async nodeReady() {
try {
await this.requestManager.send({ method: 'eth_accounts' });
const reqMgr = await this.requestManager;
await reqMgr.send({ method: 'eth_accounts' });
} catch (e) {
throw new Error(__(`Unable to connect to the blockchain endpoint on ${this.endpoint}`));
}
@ -169,8 +164,9 @@ export class Proxy {
}
forwardRequestToNode(request) {
return new Promise((resolve, reject) => {
this.requestManager.send(request, (fwdReqErr, result) => {
return new Promise(async (resolve, reject) => {
const reqMgr = await this.requestManager;
reqMgr.send(request, (fwdReqErr, result) => {
if (fwdReqErr) {
return reject(fwdReqErr);
}
@ -180,8 +176,9 @@ export class Proxy {
}
async handleSubscribe(clientSocket, request, response, cb) {
const provider = await this._createWebSocketProvider(this.endpoint);
// creates a new long-living connection to the node
const currentReqManager = this._createWeb3RequestManager(this._createWebSocketProvider());
const currentReqManager = this._createWeb3RequestManager(provider);
// kill WS connetion to the node when the client connection closes
clientSocket.on('close', () => currentReqManager.provider.disconnect());

View File

@ -224,9 +224,9 @@ class TestRunner {
const ogAccounts = this.simOptions.accounts;
Object.assign(this.simOptions, {host, port, type, protocol, accounts, client: config.blockchain && config.blockchain.client});
if (!resetServices && !deepEqual(accounts, ogAccounts)) {
return this.plugins.emitAndRunActionsForEvent("accounts:reseted", {accounts}, cb);
}
// if (!resetServices && !deepEqual(accounts, ogAccounts)) {
// return this.plugins.emitAndRunActionsForEvent("accounts:reseted", {accounts}, cb);
// }
if (!resetServices) {
return cb();