Skip to content

Commit

Permalink
refactor(@embark/rpc-manager): Simplify RPC modifications
Browse files Browse the repository at this point in the history
Managing account details inside of the RPC Manager became a bit convulted and difficult to follow due to any web3 requests inside of an `RpcModifier` communicating over the proxy and therefore to other `RpcModifier`’s or itself. It also created cases where node accounts were duplicated by way of running the `eth_accounts` modifier multiple times (the first time getting accounts from the node and subsequent times getting accounts from the modified `eth_accounts` response.

This has been simplified by having the entry point of the `rpc-manager` (`index.js`) talk directly to the node via `web3`. This allowed account/nodeAccount management to also be handled by the entry point, removing the need for each individual `RpcModifier` from having to handle these account details. The result is a much more simplified and and much easier to maintain code for RPC Manager.

The cases for which accounts can be modified (via `personal_newAccount` RPC call, and via test configuration change) are now handled in one place (the entry point) and propagated to the each `RpcModifier`.

Add `blockchain:started` command to request when the blockchain has been started. In this case, this is needed so that we know when we can create a direct connection to the node, instead of the proxy (as is the case in almost all other modules).

Extend action timeout when in debug mode.

1. These changs have made the `RpcModifier` base class essentially useless, however, it has been kept in place because it will be used for future DRY improvements to the `rpc-manager`.
2. These changes have been tested with the following DApps:
- Demo
- Test DApp
- Contracts test DApp
- Teller
  • Loading branch information
emizzle committed Mar 5, 2020
1 parent 838d421 commit 3b753e8
Show file tree
Hide file tree
Showing 18 changed files with 109 additions and 137 deletions.
4 changes: 4 additions & 0 deletions packages/core/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export interface Configuration {
wsRPC: boolean;
isDev: boolean;
client: string;
enabled: boolean;
clientConfig: {
miningMode: string
}
};
webServerConfig: {
certOptions: {
Expand Down
8 changes: 2 additions & 6 deletions packages/core/core/src/processes/processLauncher.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const child_process = require('child_process');
import { readJsonSync } from 'fs-extra';
const path = require('path');
import { isDebug } from 'embark-utils';

const constants = readJsonSync(path.join(__dirname, '../../constants.json'));

Expand All @@ -18,7 +19,7 @@ export class ProcessLauncher {
constructor(options) {
this.name = options.name || path.basename(options.modulePath);

if (this._isDebug()) {
if (isDebug()) {
const childOptions = {stdio: 'pipe', execArgv: ['--inspect-brk=' + (60000 + processCount)]};
processCount++;
this.process = child_process.fork(options.modulePath, [], childOptions);
Expand All @@ -45,11 +46,6 @@ export class ProcessLauncher {
this.events.request('process:logs:register', {processName: this.name, eventName: `process:${this.name}:log`, silent: this.silent});
}

_isDebug() {
const argvString= process.execArgv.join();
return argvString.includes('--debug') || argvString.includes('--inspect');
}

// Subscribes to messages from the child process and delegates to the right methods
_subscribeToMessages() {
const self = this;
Expand Down
4 changes: 3 additions & 1 deletion packages/core/utils/src/accountParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export default class AccountParser {
static parseAccountsConfig(accountsConfig, web3, dappPath, logger, nodeAccounts) {
let accounts = [];
if (!(accountsConfig && accountsConfig.length)) {
return nodeAccounts;
return nodeAccounts.map(account => {
return (typeof account === 'string') ? { address: account } : account;
});
}
if (accountsConfig && accountsConfig.length) {
accountsConfig.forEach(accountConfig => {
Expand Down
5 changes: 5 additions & 0 deletions packages/core/utils/src/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ export function setUpEnv(defaultEmbarkPath) {
(process.env[NODE_PATH] ? delimiter : '') +
(process.env[NODE_PATH] || '');
}

export function isDebug() {
const argvString= process.execArgv.join();
return argvString.includes('--debug') || argvString.includes('--inspect');
}
2 changes: 1 addition & 1 deletion packages/core/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export {
normalizePath,
toForwardSlashes
} from './pathUtils';
export { setUpEnv } from './env';
export { setUpEnv, isDebug } from './env';

import {
dappPath
Expand Down
3 changes: 2 additions & 1 deletion packages/embark/src/cmd/cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ class Cmd {
txDetails: options.txDetails,
node: options.node,
coverage: options.coverage,
env: options.env || 'test'
env: options.env || 'test',
sol: options.solc
});
});
}
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/geth/src/devtxs.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { __ } from 'embark-i18n';
import { Embark, EmbarkEvents } from "embark-core";
import { Embark, EmbarkEvents, Configuration } from "embark-core";
import { Logger } from "embark-logger";
import Web3 from "web3";
import { TransactionReceipt } from "web3-eth";
import constants from "embark-core/constants.json";
export default class DevTxs {
private embark: Embark;
private blockchainConfig: any;
private blockchainConfig: Configuration["blockchainConfig"];
private events: EmbarkEvents;
private logger: Logger;
private web3?: Web3;
Expand Down
29 changes: 4 additions & 25 deletions packages/plugins/rpc-manager/src/lib/eth_accounts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Callback, Embark, EmbarkEvents } from "embark-core";
const { blockchain: blockchainConstants } = require("embark-core/constants");
import { __ } from "embark-i18n";
import { Logger } from "embark-logger";
import Web3 from "web3";
import RpcModifier from "./rpcModifier";

Expand All @@ -10,24 +9,9 @@ const METHODS_TO_MODIFY = [
blockchainConstants.transactionMethods.personal_listAccounts,
];

function arrayEqual(arrayA: string[], arrayB: string[]) {
if (!(arrayA && arrayB) || arrayA.length !== arrayB.length) {
return false;
} else {
return arrayA.every((address, index) => Web3.utils.toChecksumAddress(address) === Web3.utils.toChecksumAddress(arrayB[index]));
}
}

export default class EthAccounts extends RpcModifier {
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);

this.init();
}

private async init() {
const nodeAccounts = await this.nodeAccounts;
this.rpcModifierEvents.request2("nodeAccounts:updated", nodeAccounts);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

this.embark.registerActionForEvent("blockchain:proxy:response", this.ethAccountsResponse.bind(this));
}
Expand All @@ -42,16 +26,11 @@ export default class EthAccounts extends RpcModifier {
this.logger.trace(__(`Original request/response data: ${JSON.stringify({ request: params.request, response: params.response })}`));

try {
if (!arrayEqual(params.response.result, this._nodeAccounts || [])) {
// reset backing variables so accounts is recalculated
await this.rpcModifierEvents.request2("nodeAccounts:updated", params.response.result);
}
const accounts = await this.accounts;
if (!(accounts && accounts.length)) {
if (!(this.accounts && this.accounts.length)) {
return callback(null, params);
}

params.response.result = accounts.map((acc) => acc.address || acc);
params.response.result = this.accounts.map((acc) => acc.address);
this.logger.trace(__(`Modified request/response data: ${JSON.stringify({ request: params.request, response: params.response })}`));
} catch (err) {
return callback(err);
Expand Down
16 changes: 6 additions & 10 deletions packages/plugins/rpc-manager/src/lib/eth_sendTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import async from "async";
import { Callback, Embark, EmbarkEvents } from "embark-core";
import { __ } from "embark-i18n";
import { Logger } from "embark-logger";
import Web3 from "web3";
const { blockchain: blockchainConstants } = require("embark-core/constants");
import RpcModifier from "./rpcModifier";

export default class EthSendTransaction extends RpcModifier {
private signTransactionQueue: any;
private nonceCache: any = {};
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

embark.registerActionForEvent("blockchain:proxy:request", this.ethSendTransactionRequest.bind(this));

Expand All @@ -23,9 +22,8 @@ export default class EthSendTransaction extends RpcModifier {
return callback(err, null);
}
payload.nonce = newNonce;
const web3 = await this.web3;
try {
const result = await web3.eth.accounts.signTransaction(payload, account.privateKey);
const result = await this.web3.eth.accounts.signTransaction(payload, account.privateKey);
callback(null, result.rawTransaction);
} catch (err) {
callback(err);
Expand All @@ -35,8 +33,7 @@ export default class EthSendTransaction extends RpcModifier {
}

private async getNonce(address: string, callback: Callback<any>) {
const web3 = await this.web3;
web3.eth.getTransactionCount(address, (error: any, transactionCount: number) => {
this.web3.eth.getTransactionCount(address, (error: any, transactionCount: number) => {
if (error) {
return callback(error, null);
}
Expand All @@ -57,8 +54,7 @@ export default class EthSendTransaction extends RpcModifier {
if (!(params.request.method === blockchainConstants.transactionMethods.eth_sendTransaction)) {
return callback(null, params);
}
const accounts = await this.accounts;
if (!(accounts && accounts.length)) {
if (!(this.accounts && this.accounts.length)) {
return callback(null, params);
}

Expand All @@ -67,7 +63,7 @@ export default class EthSendTransaction extends RpcModifier {

try {
// Check if we have that account in our wallet
const account = accounts.find((acc) => Web3.utils.toChecksumAddress(acc.address) === Web3.utils.toChecksumAddress(params.request.params[0].from));
const account = this.accounts.find((acc) => Web3.utils.toChecksumAddress(acc.address) === Web3.utils.toChecksumAddress(params.request.params[0].from));
if (account && account.privateKey) {
return this.signTransactionQueue.push({ payload: params.request.params[0], account }, (err: any, newPayload: any) => {
if (err) {
Expand Down
13 changes: 5 additions & 8 deletions packages/plugins/rpc-manager/src/lib/eth_signData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import Web3 from "web3";
import RpcModifier from "./rpcModifier";

export default class EthSignData extends RpcModifier {
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

this.embark.registerActionForEvent("blockchain:proxy:request", this.ethSignDataRequest.bind(this));
this.embark.registerActionForEvent("blockchain:proxy:response", this.ethSignDataResponse.bind(this));
Expand All @@ -17,10 +17,9 @@ export default class EthSignData extends RpcModifier {
}

try {
const nodeAccounts = await this.nodeAccounts;
const [fromAddr] = params.request.params;

const account = nodeAccounts.find(acc => (
const account = this.nodeAccounts.find(acc => (
Web3.utils.toChecksumAddress(acc) ===
Web3.utils.toChecksumAddress(fromAddr)
));
Expand All @@ -40,11 +39,9 @@ export default class EthSignData extends RpcModifier {
}

try {
const accounts = await this.accounts;
const nodeAccounts = await this.nodeAccounts;
const [fromAddr, data] = params.request.params;

const nodeAccount = nodeAccounts.find(acc => (
const nodeAccount = this.nodeAccounts.find(acc => (
Web3.utils.toChecksumAddress(acc) ===
Web3.utils.toChecksumAddress(fromAddr)
));
Expand All @@ -55,7 +52,7 @@ export default class EthSignData extends RpcModifier {
this.logger.trace(__(`Modifying blockchain '${params.request.method}' response:`));
this.logger.trace(__(`Original request/response data: ${JSON.stringify(params)}`));

const account = accounts.find(acc => (
const account = this.accounts.find(acc => (
Web3.utils.toChecksumAddress(acc.address) ===
Web3.utils.toChecksumAddress(fromAddr)
));
Expand Down
8 changes: 3 additions & 5 deletions packages/plugins/rpc-manager/src/lib/eth_signTypedData.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { sign, transaction } from "@omisego/omg-js-util";
import { Callback, Embark, EmbarkEvents } from "embark-core";
import { __ } from "embark-i18n";
import { Logger } from "embark-logger";
import Web3 from "web3";
import RpcModifier from "./rpcModifier";

export default class EthSignTypedData extends RpcModifier {
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

this.embark.registerActionForEvent("blockchain:proxy:request", this.ethSignTypedDataRequest.bind(this));
this.embark.registerActionForEvent("blockchain:proxy:response", this.ethSignTypedDataResponse.bind(this));
Expand Down Expand Up @@ -41,9 +40,8 @@ export default class EthSignTypedData extends RpcModifier {
this.logger.trace(__(`Original request/response data: ${JSON.stringify({ request: params.request, response: params.response })}`));

try {
const accounts = await this.accounts;
const [fromAddr, typedData] = params.request.params;
const account = accounts.find((acc) => Web3.utils.toChecksumAddress(acc.address) === Web3.utils.toChecksumAddress(fromAddr));
const account = this.accounts.find((acc) => Web3.utils.toChecksumAddress(acc.address) === Web3.utils.toChecksumAddress(fromAddr));
if (!(account && account.privateKey)) {
return callback(
new Error(__("Could not sign transaction because Embark does not have a private key associated with '%s'. " +
Expand Down
5 changes: 3 additions & 2 deletions packages/plugins/rpc-manager/src/lib/eth_subscribe.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Callback, Embark, EmbarkEvents } from "embark-core";
import { __ } from "embark-i18n";
import RpcModifier from "./rpcModifier";
import Web3 from "web3";

export default class EthSubscribe extends RpcModifier {
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

embark.registerActionForEvent("blockchain:proxy:request", this.ethSubscribeRequest.bind(this));
embark.registerActionForEvent("blockchain:proxy:response", this.ethSubscribeResponse.bind(this));
Expand Down
5 changes: 3 additions & 2 deletions packages/plugins/rpc-manager/src/lib/eth_unsubscribe.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Callback, Embark, EmbarkEvents } from "embark-core";
import { __ } from "embark-i18n";
import RpcModifier from "./rpcModifier";
import Web3 from "web3";

export default class EthUnsubscribe extends RpcModifier {

constructor(embark: Embark, rpcModifierEvents: EmbarkEvents) {
super(embark, rpcModifierEvents);
constructor(embark: Embark, rpcModifierEvents: EmbarkEvents, public nodeAccounts: string[], public accounts: any[], protected web3: Web3) {
super(embark, rpcModifierEvents, nodeAccounts, accounts, web3);

embark.registerActionForEvent("blockchain:proxy:request", this.ethUnsubscribeRequest.bind(this));
embark.registerActionForEvent("blockchain:proxy:response", this.ethUnsubscribeResponse.bind(this));
Expand Down
Loading

0 comments on commit 3b753e8

Please sign in to comment.