chore(@embark/): remove old modules blockchain-process & code-generator; remove old methods from engine.js (#1875)

chore (@embark/) remove old modules blockchain-process and code-generator

chore (@embark/) remove old module blockchain-process

chore (@embark/) remove embark blockchain & embark simulator cmds

chore (@embark/) remove old methods from engine.js

Revert "chore (@embark/) remove embark blockchain & embark simulator cmds"

This reverts commit 703a424fb9e720b9342acb4cf9d00530f7393059.

re-add cockpit modules

re-add cockpit modules
This commit is contained in:
Iuri Matias 2019-09-06 17:35:44 -04:00 committed by GitHub
parent 0b9670fd33
commit 43386ff35d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 13 additions and 4926 deletions

View File

@ -1,4 +0,0 @@
engine-strict = true
package-lock = false
save-exact = true
scripts-prepend-node-path = true

View File

@ -1,71 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.1.1](https://github.com/embark-framework/embark/compare/v4.1.0...v4.1.1) (2019-08-28)
**Note:** Version bump only for package embark-blockchain-connector
# [4.1.0](https://github.com/embark-framework/embark/compare/v4.1.0-beta.6...v4.1.0) (2019-08-12)
**Note:** Version bump only for package embark-blockchain-connector
# [4.1.0-beta.6](https://github.com/embark-framework/embark/compare/v4.1.0-beta.5...v4.1.0-beta.6) (2019-08-09)
**Note:** Version bump only for package embark-blockchain-connector
# [4.1.0-beta.5](https://github.com/embark-framework/embark/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2019-07-10)
### Bug Fixes
* **@cockpit/explorers:** consistently display "Mined on" timestamps ([52d54f0](https://github.com/embark-framework/embark/commit/52d54f0))
* **@embark/deployment:** don't over estimate gas when running tests against non-simulator nodes ([d76a82a](https://github.com/embark-framework/embark/commit/d76a82a)), closes [/github.com/trufflesuite/ganache-core/blob/8ad1ab29deccbbb4018f6961d0eb7ec984ad8fcb/lib/utils/gasEstimation.js#L33-L39](https://github.com//github.com/trufflesuite/ganache-core/blob/8ad1ab29deccbbb4018f6961d0eb7ec984ad8fcb/lib/utils/gasEstimation.js/issues/L33-L39)
# [4.1.0-beta.4](https://github.com/embark-framework/embark/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2019-06-27)
### Features
* **@embark/blockchain-connector:** Add command to get full account info ([71cb161](https://github.com/embark-framework/embark/commit/71cb161))
# [4.1.0-beta.3](https://github.com/embark-framework/embark/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2019-06-07)
**Note:** Version bump only for package embark-blockchain-connector
# [4.1.0-beta.2](https://github.com/embark-framework/embark/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2019-05-22)
**Note:** Version bump only for package embark-blockchain-connector
# [4.1.0-beta.1](https://github.com/embark-framework/embark/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2019-05-15)
**Note:** Version bump only for package embark-blockchain-connector

View File

@ -1,6 +0,0 @@
# `embark-blockchain-connecter`
> Blockchain Connector module for Embark
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -1,75 +0,0 @@
{
"name": "embark-blockchain-connector",
"version": "4.1.1",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Blockchain Connector for Embark",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/embark-blockchain-connector#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
"dapps",
"ethereum",
"ipfs",
"serverless",
"solc",
"solidity"
],
"files": [
"dist"
],
"license": "MIT",
"repository": {
"directory": "packages/embark-blockchain-connector",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"scripts": {
"build": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --root-mode upward --source-maps",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "npm-run-all lint:*",
"lint:js": "eslint src/",
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
"package": "npm pack",
"// qa": "npm-run-all lint typecheck build package",
"qa": "npm-run-all lint build package",
"reset": "npx rimraf dist embark-*.tgz package",
"start": "npm run watch",
"// typecheck": "tsc",
"watch": "run-p watch:*",
"watch:build": "npm run build -- --verbose --watch",
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
},
"eslintConfig": {
"extends": "../../.eslintrc.json"
},
"dependencies": {
"@babel/runtime-corejs2": "7.3.1",
"async": "2.6.1",
"embark-core": "^4.1.1",
"embark-i18n": "^4.1.1",
"embark-utils": "^4.1.1",
"embarkjs": "^4.1.1",
"ethereumjs-tx": "1.3.7",
"ethereumjs-util": "6.0.0",
"ganache-cli": "6.4.3",
"web3": "1.2.1"
},
"devDependencies": {
"@babel/cli": "7.2.3",
"@babel/core": "7.2.2",
"cross-env": "5.2.0",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"rimraf": "3.0.0",
"tslint": "5.16.0",
"typescript": "3.4.5"
},
"engines": {
"node": ">=8.12.0 <12.0.0",
"npm": ">=6.4.1",
"yarn": ">=1.12.3"
}
}

View File

@ -1,77 +0,0 @@
const async = require('async');
const TARGET = 0x7FFFFFFFFFFFFFFF;
const ALREADY_FUNDED = 'alreadyFunded';
function fundAccount(web3, accountAddress, hexBalance, callback) {
if (!hexBalance) {
hexBalance = TARGET;
}
const targetBalance = web3.utils.toBN(hexBalance);
let accountBalance;
let coinbaseAddress;
let lastNonce;
let gasPrice;
async.waterfall([
function getAccountBalance(next) {
web3.eth.getBalance(accountAddress, (err, balance) => {
if (err) {
return next(err);
}
balance = web3.utils.toBN(balance);
if (balance.gte(targetBalance)) {
return next(ALREADY_FUNDED);
}
accountBalance = balance;
next();
});
},
function getNeededParams(next) {
async.parallel([
function getCoinbaseAddress(paraCb) {
web3.eth.getCoinbase()
.then((address) => {
coinbaseAddress = address;
paraCb();
}).catch(paraCb);
},
function getGasPrice(paraCb) {
web3.eth.getGasPrice((err, price) => {
if (err) {
return paraCb(err);
}
gasPrice = price;
paraCb();
});
}
], (err, _result) => {
next(err);
});
},
function getNonce(next) {
web3.eth.getTransactionCount(coinbaseAddress, (err, nonce) => {
if (err) {
return next(err);
}
lastNonce = nonce;
next();
});
},
function sendTransaction(next) {
web3.eth.sendTransaction({
from: coinbaseAddress,
to: accountAddress,
value: targetBalance.sub(accountBalance),
gasPrice: gasPrice,
nonce: lastNonce
}, next);
}
], (err) => {
if (err && err !== ALREADY_FUNDED) {
return callback(err);
}
callback();
});
}
module.exports = fundAccount;

View File

@ -1,866 +0,0 @@
import { __ } from 'embark-i18n';
const Web3 = require('web3');
const async = require('async');
const Provider = require('./provider.js');
const ethUtil = require('ethereumjs-util');
const constants = require('embark-core/constants');
const embarkJsUtils = require('embarkjs').Utils;
const {bigNumberify} = require('ethers/utils/bignumber');
const RLP = require('ethers/utils/rlp');
import {AccountParser, buildUrl, dappPath, deconstructUrl} from 'embark-utils';
const WEB3_READY = 'blockchain:ready';
const BLOCK_LIMIT = 100;
const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';
// TODO: consider another name, this is the blockchain connector
class BlockchainConnector {
constructor(embark, options) {
const self = this;
this.embark = embark;
this.plugins = options.plugins;
this.logger = embark.logger;
this.events = embark.events;
this.config = embark.config;
this.web3 = options.web3;
this.isDev = options.isDev;
this.isWeb3Ready = false;
this.wait = options.wait;
this.contractsSubscriptions = [];
this.contractsEvents = [];
this.fs = embark.fs;
this.logFile = dappPath(".embark", "contractEvents.json");
this.writeLogFile = async.cargo((tasks, callback) => {
const data = this._readEvents();
tasks.forEach(task => {
data[new Date().getTime()] = task;
});
this.fs.writeJson(this.logFile, data, err => {
if (err) {
console.error(err);
}
callback();
});
});
// self.events.setCommandHandler("blockchain:ready", self.onReady.bind(this));
// self.events.setCommandHandler("blockchain:web3:isReady", (cb) => {
// cb(self.isWeb3Ready);
// });
self.events.setCommandHandler("blockchain:object", (cb) => {
cb(self);
});
self.events.setCommandHandler("blockchain:getTransaction", (txHash, cb) => {
self.getTransactionByHash(txHash, cb);
});
embark.registerActionForEvent("contracts:deploy:afterAll", this.subscribeToContractEvents.bind(this));
if (!this.web3) {
this.initWeb3(err => {
if (err) {
this.logger.error(__('Error initiating Web3 provider'), err.message || err);
}
});
} else {
this.isWeb3Ready = true;
}
this.registerServiceCheck();
this.registerRequests();
this.registerAPIRequests();
this.registerEvents();
this.subscribeToPendingTransactions();
}
initWeb3(cb) {
if (!cb) {
cb = function(){};
}
if (this.isWeb3Ready) {
this.events.emit(WEB3_READY);
return cb();
}
const self = this;
this.web3 = new Web3();
if (self.wait) {
self.wait = false;
return cb();
}
if (this.config.blockchainConfig.type === 'vm') {
return this._setupVM(cb);
}
let {type, host, port, protocol} = deconstructUrl(this.config.blockchainConfig.endpoint);
if (!protocol) {
protocol = (type === "rpc") ? 'http' : 'ws';
}
if (!BlockchainConnector.ACCEPTED_TYPES.includes(type)) {
this.logger.error(__("contracts config error: unknown deployment type %s", type));
this.logger.error(__("Accepted types are: %s", BlockchainConnector.ACCEPTED_TYPES.join(', ')));
}
if (type === 'rpc') {
this.logger.warn('Using RPC as deployment connection type is deprecated. It is recommended to use WS.');
}
protocol = (type === "rpc") ? protocol : 'ws';
const web3Endpoint = buildUrl(protocol, host, port);
const providerOptions = {
web3: this.web3,
blockchainConfig: this.config.blockchainConfig,
logger: this.logger,
isDev: this.isDev,
type: type,
web3Endpoint,
events: this.events,
fs: this.fs
};
this.provider = new Provider(providerOptions);
// self.events.request("processes:launch", "blockchain", (err) => {
// if (err) {
// return self.logger.error(err);
// }
// setTimeout(() => {
self.provider.startWeb3Provider(async () => {
try {
const blockNumber = await self.web3.eth.getBlockNumber();
await self.web3.eth.getBlock(blockNumber);
self.provider.fundAccounts(() => {
self._emitWeb3Ready();
cb();
});
} catch (e) {
const errorMessage = e.message || e;
if (errorMessage.indexOf('no suitable peers available') > 0) {
self.logger.warn(errorMessage);
self.logger.warn(__('Your node is probably not synchronized. Wait until your node is synchronized before deploying'));
process.exit(1);
}
self.logger.error(errorMessage);
cb(errorMessage);
}
try {
const id = await this.getNetworkId();
let networkId = self.config.blockchainConfig.networkId;
if (!networkId &&
constants.blockchain.networkIds[self.config.blockchainConfig.networkType]) {
networkId = constants.blockchain.networkIds[self.config.blockchainConfig.networkType];
}
if (networkId && id.toString() !== networkId.toString()) {
self.logger.warn(__('Connected to a blockchain node on network {{realId}} while your config specifies {{configId}}', {realId: id, configId: networkId}));
self.logger.warn(__('Make sure you started the right blockchain node'));
}
} catch (e) {
console.error(e);
}
});
// });
}
_setupVM(cb) {
const sim = this._getSimulator();
const coverage = !!this.config.blockchainConfig.coverage;
let accounts = null;
if (this.config.blockchainConfig.accounts) {
accounts = AccountParser.parseAccountsConfig(this.config.blockchainConfig.accounts, this.web3, dappPath());
accounts = accounts.map((account) => {
if (!account.hexBalance) {
account.hexBalance = BALANCE_10_ETHER_IN_HEX;
}
return {balance: account.hexBalance, secretKey: account.privateKey};
});
}
const options = Object.assign(this.config.blockchainConfig.endpoint ? deconstructUrl(this.config.blockchainConfig.endpoint): {}, {
gasPrice: "0x01",
gasLimit: "0xfffffffffffff",
allowUnlimitedContractSize: coverage,
accounts
});
this.provider = sim.provider(options);
if (coverage) {
// Here we patch the sendAsync method on the provider. The goal behind this is to force pure/constant/view calls to become
// transactions, so that we can pull in execution traces and account for those executions in code coverage.
//
// Instead of a simple call, here's what happens:
//
// 1) A transaction is sent with the same payload, and a pre-defined gas price;
// 2) We wait for the transaction to be mined by asking for the receipt;
// 3) Once we get the receipt back, we dispatch the real call and pass the original callback;
//
// This will still allow tests to get the return value from the call and run contracts unmodified.
this.provider.realSendAsync = this.provider.sendAsync.bind(this.provider);
this.provider.sendAsync = (payload, cb) => {
if(payload.method !== 'eth_call') {
return this.provider.realSendAsync(payload, cb);
}
this.events.request('reporter:toggleGasListener');
let newParams = Object.assign({}, payload.params[0]);
let newPayload = {
id: payload.id + 1,
method: constants.blockchain.transactionMethods.eth_sendTransaction,
params: [newParams],
jsonrpc: payload.jsonrpc
};
this.provider.realSendAsync(newPayload, (_err, response) => {
let txHash = response.result;
this.web3.eth.getTransactionReceipt(txHash, (_err, _res) => {
this.events.request('reporter:toggleGasListener');
this.provider.realSendAsync(payload, cb);
});
});
};
}
this.web3.setProvider(this.provider);
this._emitWeb3Ready();
cb();
}
_emitWeb3Ready() {
this.registerWeb3Object(() => {
this.isWeb3Ready = true;
this.events.emit(WEB3_READY);
});
this.subscribeToPendingTransactions();
}
_getSimulator() {
try {
return require('ganache-cli');
} catch (e) {
const moreInfo = 'For more information see https://github.com/trufflesuite/ganache-cli';
if (e.code === 'MODULE_NOT_FOUND') {
this.logger.error(__('Simulator not found; Please install it with "%s"', 'npm install ganache-cli --save'));
this.logger.error(moreInfo);
throw e;
}
this.logger.error("==============");
this.logger.error(__("Tried to load Ganache CLI (testrpc), but an error occurred. This is a problem with Ganache CLI"));
this.logger.error(moreInfo);
this.logger.error("==============");
throw e;
}
}
registerEvents() {
this.events.on('check:wentOffline:Ethereum', () => {
this.logger.warn('Ethereum went offline: stopping web3 provider...');
this.provider.stop();
this.isWeb3Ready = false;
});
this.events.on('blockchain:contracts:event', this._saveEvent.bind(this));
}
onReady(callback) {
if (this.isWeb3Ready) {
return callback();
}
this.events.once(WEB3_READY, () => {
callback();
});
}
registerServiceCheck() {
const self = this;
const NO_NODE = 'noNode';
this.events.request("services:register", 'Ethereum', function(cb) {
async.waterfall([
function checkNodeConnection(next) {
if (!self.provider || !self.provider.connected()) {
return next(NO_NODE, {name: "No Blockchain node found", status: 'off'});
}
next();
},
function checkVersion(next) {
// TODO: web3_clientVersion method is currently not implemented in web3.js 1.x
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => {
if (err || !version) {
self.isWeb3Ready = false;
return next(null, {name: "Ethereum node not found", status: 'off'});
}
if (version.indexOf("/") < 0) {
self.events.emit(WEB3_READY);
self.isWeb3Ready = true;
return next(null, {name: version, status: 'on'});
}
let nodeName = version.split("/")[0];
let versionNumber = version.split("/")[1].split("-")[0];
let name = nodeName + " " + versionNumber + " (Ethereum)";
self.events.emit(WEB3_READY);
self.isWeb3Ready = true;
return next(null, {name: name, status: 'on'});
});
}
], (err, statusObj) => {
if (err && err !== NO_NODE) {
return cb(err);
}
cb(statusObj);
});
}, 5000, 'off');
}
registerRequests() {
const self = this;
this.events.setCommandHandler("blockchain:reset", function(cb) {
self.isWeb3Ready = false;
self.initWeb3((err) => {
if (err) {
return cb(err);
}
self.events.emit('blockchain:reseted');
cb();
});
});
this.events.setCommandHandler("blockchain:get", function(cb) {
cb(self.web3);
});
this.events.setCommandHandler("blockchain:defaultAccount:get", function(cb) {
cb(self.defaultAccount());
});
this.events.setCommandHandler("blockchain:defaultAccount:set", function(account, cb) {
self.setDefaultAccount(account);
cb();
});
this.events.setCommandHandler("blockchain:getAccounts", function(cb) {
self.getAccounts(cb);
});
this.events.setCommandHandler("blockchain:getBalance", function(address, cb) {
self.getBalance(address, cb);
});
this.events.setCommandHandler("blockchain:block:byNumber", function(blockNumber, cb) {
self.getBlock(blockNumber, cb);
});
this.events.setCommandHandler("blockchain:block:byHash", function(blockHash, cb) {
self.getBlock(blockHash, cb);
});
this.events.setCommandHandler("blockchain:gasPrice", function(cb) {
self.getGasPrice(cb);
});
this.events.setCommandHandler("blockchain:networkId", function(cb) {
self.getNetworkId().then(cb);
});
this.events.setCommandHandler("blockchain:contract:create", function(params, cb) {
cb(self.ContractObject(params));
});
}
registerAPIRequests() {
const self = this;
let plugin = self.plugins.createPlugin('blockchain', {});
plugin.registerAPICall(
'get',
'/embark-api/blockchain/accounts',
(req, res) => {
self.getAccountsWithTransactionCount(res.send.bind(res));
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/accounts/:address',
(req, res) => {
self.getAccount(req.params.address, res.send.bind(res));
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/blocks',
(req, res) => {
const from = parseInt(req.query.from, 10);
const limit = req.query.limit || 10;
self.getBlocks(from, limit, !!req.query.txObjects, !!req.query.txReceipts, res.send.bind(res));
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/blocks/:blockNumber',
(req, res) => {
self.getBlock(req.params.blockNumber, (err, block) => {
if (err) {
self.logger.error(err);
}
res.send(block);
});
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/transactions',
(req, res) => {
let blockFrom = parseInt(req.query.blockFrom, 10);
let blockLimit = req.query.blockLimit || 10;
self.getTransactions(blockFrom, blockLimit, res.send.bind(res));
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/transactions/:hash',
(req, res) => {
self.getTransactionByHash(req.params.hash, (err, transaction) => {
if (!err) return res.send(transaction);
self.getTransactionByRawTransactionHash(req.params.hash, (err, transaction) => {
if(err) return res.send({ error: "Could not find or decode transaction hash" });
res.send(transaction);
});
});
}
);
plugin.registerAPICall(
'ws',
'/embark-api/blockchain/blockHeader',
(ws) => {
self.events.on('block:header', (block) => {
ws.send(JSON.stringify({block: block}), () => {});
});
}
);
plugin.registerAPICall(
'ws',
'/embark-api/blockchain/contracts/event',
(ws) => {
this.events.on('blockchain:contracts:event', (data) => {
ws.send(JSON.stringify(data), () => {});
});
}
);
plugin.registerAPICall(
'get',
'/embark-api/blockchain/contracts/events',
(_req, res) => {
res.send(JSON.stringify(this._getEvents()));
}
);
plugin.registerAPICall(
'post',
'/embark-api/messages/sign',
(req, res) => {
const signer = req.body.address;
const message = req.body.message;
this.web3.eth.sign(message, signer).then(signature => {
res.send({signer, signature, message});
}).catch(e => res.send({ error: e.message }));
}
);
plugin.registerAPICall(
'post',
'/embark-api/messages/verify',
(req, res) => {
let signature;
try {
signature = JSON.parse(req.body.message);
} catch(e) {
return res.send({ error: e.message });
}
this.web3.eth.personal.ecRecover(signature.message, signature.signature)
.then(address => res.send({address}))
.catch(e => res.send({ error: e.message }));
}
);
}
getAccountsWithTransactionCount(callback) {
let self = this;
self.getAccounts((err, addresses) => {
let accounts = [];
async.eachOf(addresses, (address, index, eachCb) => {
let account = {address, index};
async.waterfall([
function(callback) {
self.getTransactionCount(address, (err, count) => {
if (err) {
self.logger.error(err);
account.transactionCount = 0;
} else {
account.transactionCount = count;
}
callback(null, account);
});
},
function(account, callback) {
self.getBalance(address, (err, balance) => {
if (err) {
self.logger.error(err);
account.balance = 0;
} else {
account.balance = self.web3.utils.fromWei(balance);
}
callback(null, account);
});
}
], function(_err, account) {
accounts.push(account);
eachCb();
});
}, function() {
callback(accounts);
});
});
}
getAccount(address, callback) {
let self = this;
async.waterfall([
function(next) {
self.getAccountsWithTransactionCount((accounts) => {
let account = accounts.find((a) => a.address === address);
if (!account) {
return next("No account found with this address");
}
next(null, account);
});
},
function(account, next) {
self.getBlockNumber((err, blockNumber) => {
if (err) {
self.logger.error(err);
next(err);
} else {
next(null, blockNumber, account);
}
});
},
function(blockNumber, account, next) {
self.getTransactions(blockNumber - BLOCK_LIMIT, BLOCK_LIMIT, (transactions) => {
account.transactions = transactions.filter((transaction) => transaction.from === address);
next(null, account);
});
}
], function(err, result) {
if (err) {
callback();
}
callback(result);
});
}
getTransactions(blockFrom, blockLimit, callback) {
this.getBlocks(blockFrom, blockLimit, true, true, (blocks) => {
let transactions = blocks.reduce((acc, block) => {
if (!block || !block.transactions) {
return acc;
}
return acc.concat(block.transactions);
}, []);
callback(transactions);
});
}
getBlocks(from, limit, returnTransactionObjects, includeTransactionReceipts, callback) {
let self = this;
let blocks = [];
async.waterfall([
function(next) {
if (!isNaN(from)) {
return next();
}
self.getBlockNumber((err, blockNumber) => {
if (err) {
self.logger.error(err);
from = 0;
} else {
from = blockNumber;
}
next();
});
},
function(next) {
async.times(limit, function(n, eachCb) {
self.web3.eth.getBlock(from - n, returnTransactionObjects, function(err, block) {
if (err) {
// FIXME Returns an error because we are too low
return eachCb();
}
if (!block) {
return eachCb();
}
if (!(returnTransactionObjects && includeTransactionReceipts) ||
!(block.transactions && block.transactions.length)) {
blocks.push(block);
return eachCb();
}
return Promise.all(block.transactions.map(tx => (
self.web3.eth.getTransactionReceipt(tx.hash)
)))
.then(receipts => {
block.transactions.forEach((tx, index) => {
tx['receipt'] = receipts[index];
tx['timestamp'] = block.timestamp;
});
blocks.push(block);
eachCb();
})
.catch((err) => {
self.logger.error(err.message || err);
eachCb();
});
});
}, next);
}
], function() {
callback(blocks);
});
}
defaultAccount() {
return this.web3.eth.defaultAccount;
}
getBlockNumber(cb) {
return this.web3.eth.getBlockNumber(cb);
}
setDefaultAccount(account) {
this.web3.eth.defaultAccount = account;
}
getAccounts(cb) {
this.web3.eth.getAccounts(cb);
}
getTransactionCount(address, cb) {
this.web3.eth.getTransactionCount(address, cb);
}
getBalance(address, cb) {
this.web3.eth.getBalance(address, cb);
}
getCode(address, cb) {
this.web3.eth.getCode(address, cb);
}
getBlock(blockNumber, cb) {
this.web3.eth.getBlock(blockNumber, true, (err, block) => {
if (err) return cb(err);
if (block.transactions && block.transactions.length) {
block.transactions.forEach(tx => {
tx.timestamp = block.timestamp;
});
}
cb(null, block);
});
}
getTransactionByHash(hash, cb) {
this.web3.eth.getTransaction(hash, cb);
}
getTransactionByRawTransactionHash(hash, cb) {
let rawData, decoded;
try {
rawData = Buffer.from(ethUtil.stripHexPrefix(hash), 'hex');
decoded = RLP.decode(rawData);
} catch(e) {
return cb("could not decode transaction");
}
const [
nonce,
gasPrice,
gasLimit,
to,
value,
data,
v,
r,
s
] = decoded;
const transaction = {
nonce: bigNumberify(nonce).toNumber(),
gasPrice: bigNumberify(gasPrice).toNumber(),
gasLimit: bigNumberify(gasLimit).toNumber(),
data: data,
v: `0x${v.toString('hex').toLowerCase()}`,
r: `0x${r.toString('hex').toLowerCase()}`,
s: `0x${s.toString('hex').toLowerCase()}`,
value: value.toString('utf8'),
to: `0x${to.toString('hex').toLowerCase()}`
};
cb(null, transaction);
}
getGasPrice(cb) {
const self = this;
this.onReady(() => {
self.web3.eth.getGasPrice(cb);
});
}
getClientVersion(cb) {
this.web3._requestManager.send({method: 'web3_clientVersion', params: []}, cb);
}
getNetworkId() {
return this.web3.eth.net.getId();
}
getTransaction(hash, cb) {
return this.web3.eth.getTransaction(hash, cb);
}
ContractObject(params) {
return new this.web3.eth.Contract(params.abi, params.address);
}
deployContractObject(contractObject, params) {
return contractObject.deploy({arguments: params.arguments, data: params.data});
}
estimateDeployContractGas(deployObject, cb) {
return deployObject.estimateGas().then((gasValue) => {
cb(null, gasValue);
}).catch(cb);
}
deployContractFromObject(deployContractObject, params, cb, hashCb) {
embarkJsUtils.secureSend(this.web3, deployContractObject, {
from: params.from, gas: params.gas, gasPrice: params.gasPrice
}, true, cb, hashCb);
}
determineDefaultAccount(cb) {
const self = this;
self.getAccounts(function(err, accounts) {
if (err) {
self.logger.error(err);
return cb(new Error(err));
}
let accountConfig = self.config.blockchainConfig.account;
let selectedAccount = accountConfig && accountConfig.address;
const defaultAccount = selectedAccount || accounts[0];
self.setDefaultAccount(defaultAccount);
cb(null, defaultAccount);
});
}
registerWeb3Object(cb = () => {}) {
// doesn't feel quite right, should be a cmd or plugin method
// can just be a command without a callback
this.events.emit("runcode:register", "web3", this.web3, cb);
}
subscribeToPendingTransactions() {
const self = this;
this.onReady(() => {
if (self.logsSubscription) {
self.logsSubscription.unsubscribe();
}
self.logsSubscription = self.web3.eth
.subscribe('newBlockHeaders', () => {})
.on("data", function (blockHeader) {
self.events.emit('block:header', blockHeader);
});
if (self.pendingSubscription) {
self.pendingSubscription.unsubscribe();
}
self.pendingSubscription = self.web3.eth
.subscribe('pendingTransactions', function(error, transaction){
if (!error) {
self.events.emit('block:pending:transaction', transaction);
}
});
});
}
subscribeToContractEvents(callback) {
this.contractsSubscriptions.forEach((eventEmitter) => {
const reqMgr = eventEmitter.options.requestManager;
// attempting an eth_unsubscribe when not connected throws an
// "connection not open on send()" error
if(reqMgr && reqMgr.provider && reqMgr.provider.connected) {
eventEmitter.unsubscribe();
}
});
this.contractsSubscriptions = [];
this.events.request("contracts:list", (_err, contractsList) => {
contractsList.forEach(contractObject => {
if (!contractObject.deployedAddress){
return;
}
const contract = this.ContractObject({abi: contractObject.abiDefinition, address: contractObject.deployedAddress});
const eventEmitter = contract.events.allEvents();
this.contractsSubscriptions.push(eventEmitter);
eventEmitter.on('data', (data) => {
const dataWithName = Object.assign(data, {name: contractObject.className});
this.contractsEvents.push(dataWithName);
this.events.emit('blockchain:contracts:event', dataWithName);
});
});
callback();
});
}
_getEvents() {
const data = this._readEvents();
return Object.values(data).reverse();
}
_saveEvent(event) {
this.writeLogFile.push(event);
}
_readEvents() {
this.fs.ensureFileSync(this.logFile);
try {
return JSON.parse(this.fs.readFileSync(this.logFile));
} catch(_error) {
return {};
}
}
}
BlockchainConnector.ACCEPTED_TYPES = ['rpc', 'ws', 'vm'];
module.exports = BlockchainConnector;

View File

@ -1,191 +0,0 @@
import {__} from 'embark-i18n';
const async = require('async');
const { AccountParser, dappPath } = require('embark-utils');
const fundAccount = require('./fundAccount');
const constants = require('embark-core/constants');
const Transaction = require('ethereumjs-tx');
const ethUtil = require('ethereumjs-util');
class Provider {
constructor(options) {
this.web3 = options.web3;
this.blockchainConfig = options.blockchainConfig;
this.type = options.type;
this.web3Endpoint = options.web3Endpoint;
this.logger = options.logger;
this.isDev = options.isDev;
this.events = options.events;
this.nonceCache = {};
this.accounts = [];
this.events.setCommandHandler("blockchain:provider:contract:accounts:get", cb => {
const accounts = this.accounts.map(a => a.address || a);
cb(null, accounts);
});
this.events.setCommandHandler("blockchain:provider:contract:accounts:getAll", (cb) => {
cb(null, this.accounts);
});
}
getNonce(address, callback) {
this.web3.eth.getTransactionCount(address, (_error, transactionCount) => {
if(this.nonceCache[address] === undefined) {
this.nonceCache[address] = -1;
}
if (transactionCount > this.nonceCache[address]) {
this.nonceCache[address] = transactionCount;
return callback(this.nonceCache[address]);
}
this.nonceCache[address]++;
callback(this.nonceCache[address]);
});
}
startWeb3Provider(callback) {
const self = this;
if (this.type === 'rpc') {
self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint);
} else if (this.type === 'ws') {
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the following error:
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {
headers: {Origin: constants.embarkResourceOrigin},
// TODO remove this when Geth fixes this: https://github.com/ethereum/go-ethereum/issues/16846
clientConfig: {
fragmentationThreshold: 81920
}
});
self.provider.on('error', () => self.logger.error('Websocket Error'));
self.provider.on('end', () => self.logger.error('Websocket connection ended'));
} else {
return callback(__("contracts config error: unknown deployment type %s", this.type));
}
self.web3.setProvider(self.provider);
self.web3.eth.getAccounts((err, accounts = []) => {
if (err) {
self.logger.warn('Error while getting the node\'s accounts.', err.message || err);
}
self.accounts = AccountParser.parseAccountsConfig(self.blockchainConfig.accounts, self.web3, dappPath(), self.logger, accounts);
if (!self.accounts.length) {
self.accounts = accounts;
}
self.addresses = [];
self.accounts.forEach(account => {
self.addresses.push(account.address || account);
if (account.privateKey) {
self.web3.eth.accounts.wallet.add(account);
}
});
// Normalize addresses and remove duplicates
self.addresses = [...new Set(self.addresses.map(ethUtil.toChecksumAddress))];
if (self.accounts.length) {
self.web3.eth.defaultAccount = self.addresses[0];
}
const realSend = self.provider.send.bind(self.provider);
// Allow to run transaction in parallel by resolving
// the nonce manually.
// For each transaction, resolve the nonce by taking the
// max of current transaction count and the cache we keep
// locally.
// Deconstruct the transaction and update the nonce.
// Before updating the transaction, it must be signed.
self.runTransaction = async.queue(({payload}, callback) => {
const rawTx = payload.params[0];
const rawData = Buffer.from(ethUtil.stripHexPrefix(rawTx), 'hex');
const tx = new Transaction(rawData, 'hex');
const address = '0x' + tx.getSenderAddress().toString('hex').toLowerCase();
self.getNonce(address, (newNonce) => {
tx.nonce = newNonce;
const key = ethUtil.stripHexPrefix(self.web3.eth.accounts.wallet[address].privateKey);
const privKey = Buffer.from(key, 'hex');
tx.sign(privKey);
payload.params[0] = '0x' + tx.serialize().toString('hex');
return realSend(payload, (error, result) => {
self.web3.eth.getTransaction(result.result, () => {
callback(error, result);
});
});
});
}, 1);
self.provider.send = function(payload, cb) {
if (payload.method === 'eth_accounts' || payload.method === 'personal_listAccounts') {
return realSend(payload, function(err, result) {
if (err) {
return cb(err);
}
if (self.accounts.length) {
result.result = [
...new Set([
...self.addresses,
...result.result.map(ethUtil.toChecksumAddress)
])
];
}
cb(null, result);
});
} else if (payload.method === constants.blockchain.transactionMethods.eth_sendRawTransaction) {
return self.runTransaction.push({payload}, cb);
}
realSend(payload, cb);
};
callback();
});
}
connected() {
if (this.type === 'rpc') {
return !!this.provider;
} else if (this.type === 'ws') {
return this.provider && this.provider.connection._connection && this.provider.connection._connection.connected;
}
return false;
}
stop() {
if (this.provider && this.provider.removeAllListeners) {
this.provider.removeAllListeners('connect');
this.provider.removeAllListeners('error');
this.provider.removeAllListeners('end');
this.provider.removeAllListeners('data');
this.provider.responseCallbacks = {};
}
this.provider = null;
this.web3.setProvider(null);
}
fundAccounts(callback) {
const self = this;
if (!self.accounts.length) {
return callback();
}
if (!self.isDev) {
return callback();
}
async.eachLimit(self.accounts, 1, (account, eachCb) => {
if (!account.address) {
return eachCb();
}
fundAccount(self.web3, account.address, account.hexBalance, eachCb);
}, callback);
}
}
module.exports = Provider;

View File

@ -1,4 +0,0 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
}

View File

@ -1,3 +0,0 @@
{
"extends": "../../tslint.json"
}

View File

@ -1,4 +0,0 @@
engine-strict = true
package-lock = false
save-exact = true
scripts-prepend-node-path = true

View File

@ -1,64 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.1.1](https://github.com/embark-framework/embark/compare/v4.1.0...v4.1.1) (2019-08-28)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0](https://github.com/embark-framework/embark/compare/v4.1.0-beta.6...v4.1.0) (2019-08-12)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.6](https://github.com/embark-framework/embark/compare/v4.1.0-beta.5...v4.1.0-beta.6) (2019-08-09)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.5](https://github.com/embark-framework/embark/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2019-07-10)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.4](https://github.com/embark-framework/embark/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2019-06-27)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.3](https://github.com/embark-framework/embark/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2019-06-07)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.2](https://github.com/embark-framework/embark/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2019-05-22)
**Note:** Version bump only for package embark-blockchain-process
# [4.1.0-beta.1](https://github.com/embark-framework/embark/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2019-05-15)
**Note:** Version bump only for package embark-blockchain-process

View File

@ -1,6 +0,0 @@
# `embark-blockchain-process`
> Blockchain Process abstraction for Embark
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -1,77 +0,0 @@
{
"name": "embark-blockchain-process",
"version": "4.1.1",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Blockchain process abstraction for Embark",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/embark-blockchain-process#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
"dapps",
"ethereum",
"ipfs",
"serverless",
"solc",
"solidity"
],
"files": [
"dist"
],
"license": "MIT",
"repository": {
"directory": "packages/embark-blockchain-process",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"scripts": {
"build": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --root-mode upward --source-maps",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "npm-run-all lint:*",
"lint:js": "eslint src/",
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
"package": "npm pack",
"// qa": "npm-run-all lint typecheck build package",
"qa": "npm-run-all lint build package",
"reset": "npx rimraf dist embark-*.tgz package",
"start": "npm run watch",
"// typecheck": "tsc",
"watch": "run-p watch:*",
"watch:build": "npm run build -- --verbose --watch",
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
},
"eslintConfig": {
"extends": "../../.eslintrc.json"
},
"dependencies": {
"@babel/runtime-corejs2": "7.3.1",
"async": "2.6.1",
"embark-core": "^4.1.1",
"embark-i18n": "^4.1.1",
"embark-logger": "^4.1.1",
"embark-utils": "^4.1.1",
"fs-extra": "7.0.1",
"netcat": "1.3.5",
"pkg-up": "2.0.0",
"semver": "5.6.0",
"shelljs": "0.8.3",
"ws": "7.1.2"
},
"devDependencies": {
"@babel/cli": "7.2.3",
"@babel/core": "7.2.2",
"cross-env": "5.2.0",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"rimraf": "3.0.0",
"tslint": "5.16.0",
"typescript": "3.4.5"
},
"engines": {
"node": ">=8.12.0 <12.0.0",
"npm": ">=6.4.1",
"yarn": ">=1.12.3"
}
}

View File

@ -1,446 +0,0 @@
import { __ } from 'embark-i18n';
const fs = require('fs-extra');
const async = require('async');
const {spawn, exec} = require('child_process');
const path = require('path');
const constants = require('embark-core/constants');
const GethClient = require('./gethClient.js');
const ParityClient = require('./parityClient.js');
import { IPC } from 'embark-core';
import { compact, dappPath, defaultHost, dockerHostSwap, embarkPath} from 'embark-utils';
const Logger = require('embark-logger');
// time between IPC connection attempts (in ms)
const IPC_CONNECT_INTERVAL = 2000;
/*eslint complexity: ["error", 50]*/
var Blockchain = function(userConfig, clientClass) {
this.userConfig = userConfig;
this.env = userConfig.env || 'development';
this.isDev = userConfig.isDev;
this.onReadyCallback = userConfig.onReadyCallback || (() => {});
this.onExitCallback = userConfig.onExitCallback;
this.logger = userConfig.logger || new Logger({logLevel: 'debug', context: constants.contexts.blockchain}); // do not pass in events as we don't want any log events emitted
this.events = userConfig.events;
this.isStandalone = userConfig.isStandalone;
this.certOptions = userConfig.certOptions;
let defaultWsApi = clientClass.DEFAULTS.WS_API;
if (this.isDev) defaultWsApi = clientClass.DEFAULTS.DEV_WS_API;
this.config = {
silent: this.userConfig.silent,
client: this.userConfig.client,
ethereumClientBin: this.userConfig.ethereumClientBin || this.userConfig.client,
networkType: this.userConfig.networkType || clientClass.DEFAULTS.NETWORK_TYPE,
networkId: this.userConfig.networkId || clientClass.DEFAULTS.NETWORK_ID,
genesisBlock: this.userConfig.genesisBlock || false,
datadir: this.userConfig.datadir,
mineWhenNeeded: this.userConfig.mineWhenNeeded || false,
rpcHost: dockerHostSwap(this.userConfig.rpcHost) || defaultHost,
rpcPort: this.userConfig.rpcPort || 8545,
rpcCorsDomain: this.userConfig.rpcCorsDomain || false,
rpcApi: this.userConfig.rpcApi || clientClass.DEFAULTS.RPC_API,
port: this.userConfig.port || 30303,
nodiscover: this.userConfig.nodiscover || false,
mine: this.userConfig.mine || false,
account: {},
whisper: (this.userConfig.whisper !== false),
maxpeers: ((this.userConfig.maxpeers === 0) ? 0 : (this.userConfig.maxpeers || 25)),
bootnodes: this.userConfig.bootnodes || "",
wsRPC: (this.userConfig.wsRPC !== false),
wsHost: dockerHostSwap(this.userConfig.wsHost) || defaultHost,
wsPort: this.userConfig.wsPort || 8546,
wsOrigins: this.userConfig.wsOrigins || false,
wsApi: this.userConfig.wsApi || defaultWsApi,
vmdebug: this.userConfig.vmdebug || false,
targetGasLimit: this.userConfig.targetGasLimit || false,
syncMode: this.userConfig.syncMode || this.userConfig.syncmode,
verbosity: this.userConfig.verbosity
};
this.devFunds = null;
if (this.userConfig.accounts) {
const nodeAccounts = this.userConfig.accounts.find(account => account.nodeAccounts);
if (nodeAccounts) {
this.config.account = {
numAccounts: nodeAccounts.numAddresses || 1,
password: nodeAccounts.password,
balance: nodeAccounts.balance
};
}
}
if (this.userConfig === {} || this.userConfig.default || JSON.stringify(this.userConfig) === '{"client":"geth"}') {
if (this.env === 'development') {
this.isDev = true;
} else {
this.config.genesisBlock = embarkPath("templates/boilerplate/config/privatenet/genesis.json");
}
this.config.datadir = dappPath(".embark/development/datadir");
this.config.wsOrigins = this.config.wsOrigins || "http://localhost:8000";
this.config.rpcCorsDomain = this.config.rpcCorsDomain || "http://localhost:8000";
this.config.targetGasLimit = 8000000;
}
this.config.account.devPassword = path.join(this.config.datadir, "devPassword");
const spaceMessage = 'The path for %s in blockchain config contains spaces, please remove them';
if (this.config.datadir && this.config.datadir.indexOf(' ') > 0) {
this.logger.error(__(spaceMessage, 'datadir'));
process.exit(1);
}
if (this.config.account.password && this.config.account.password.indexOf(' ') > 0) {
this.logger.error(__(spaceMessage, 'accounts.password'));
process.exit(1);
}
if (this.config.genesisBlock && this.config.genesisBlock.indexOf(' ') > 0) {
this.logger.error(__(spaceMessage, 'genesisBlock'));
process.exit(1);
}
this.client = new clientClass({config: this.config, env: this.env, isDev: this.isDev});
this.initStandaloneProcess();
};
/**
* Polls for a connection to an IPC server (generally this is set up
* in the Embark process). Once connected, any logs logged to the
* Logger will be shipped off to the IPC server. In the case of `embark
* run`, the BlockchainListener module is listening for these logs.
*
* @returns {void}
*/
Blockchain.prototype.initStandaloneProcess = function () {
if (this.isStandalone) {
let logQueue = [];
// on every log logged in logger (say that 3x fast), send the log
// to the IPC serve listening (only if we're connected of course)
this.logger.events.on('log', (logLevel, message) => {
if (this.ipc.connected) {
this.ipc.request('blockchain:log', {logLevel, message});
} else {
logQueue.push({logLevel, message});
}
});
this.ipc = new IPC({ipcRole: 'client'});
// Wait for an IPC server to start (ie `embark run`) by polling `.connect()`.
// Do not kill this interval as the IPC server may restart (ie restart
// `embark run` without restarting `embark blockchain`)
setInterval(() => {
if (!this.ipc.connected) {
this.ipc.connect(() => {
if (this.ipc.connected) {
logQueue.forEach(message => { this.ipc.request('blockchain:log', message); });
logQueue = [];
this.ipc.client.on('process:blockchain:stop', () => {
this.kill();
process.exit(0);
});
}
});
}
}, IPC_CONNECT_INTERVAL);
}
};
Blockchain.prototype.runCommand = function (cmd, options, callback) {
this.logger.info(__("running: %s", cmd.underline).green);
if (this.config.silent) {
options.silent = true;
}
return exec(cmd, options, callback);
};
Blockchain.prototype.run = function () {
var self = this;
this.logger.info("===============================================================================".magenta);
this.logger.info("===============================================================================".magenta);
this.logger.info(__("Embark Blockchain using %s", self.client.prettyName.underline).magenta);
this.logger.info("===============================================================================".magenta);
this.logger.info("===============================================================================".magenta);
if (self.client.name === constants.blockchain.clients.geth) this.checkPathLength();
let address = '';
async.waterfall([
function checkInstallation(next) {
self.isClientInstalled((err) => {
if (err) {
return next({message: err});
}
next();
});
},
function init(next) {
if (self.isDev) {
return self.initDevChain((err) => {
next(err);
});
}
return self.initChainAndGetAddress((err, addr) => {
address = addr;
next(err);
});
},
function getMainCommand(next) {
self.client.mainCommand(address, function (cmd, args) {
next(null, cmd, args);
}, true);
}
], function(err, cmd, args) {
if (err) {
self.logger.error(err.message);
return;
}
args = compact(args);
let full_cmd = cmd + " " + args.join(' ');
self.logger.info(__("running: %s", full_cmd.underline).green);
self.child = spawn(cmd, args, {cwd: process.cwd()});
self.child.on('error', (err) => {
err = err.toString();
self.logger.error('Blockchain error: ', err);
if (self.env === 'development' && err.indexOf('Failed to unlock') > 0) {
self.logger.error('\n' + __('Development blockchain has changed to use the --dev option.').yellow);
self.logger.error(__('You can reset your workspace to fix the problem with').yellow + ' embark reset'.cyan);
self.logger.error(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
}
});
// TOCHECK I don't understand why stderr and stdout are reverted.
// This happens with Geth and Parity, so it does not seems a client problem
self.child.stdout.on('data', (data) => {
self.logger.info(`${self.client.name} error: ${data}`);
});
self.child.stderr.on('data', async (data) => {
data = data.toString();
if (!self.readyCalled && self.client.isReady(data)) {
self.readyCalled = true;
self.readyCallback();
}
self.logger.info(`${self.client.name}: ${data}`);
});
self.child.on('exit', (code) => {
let strCode;
if (code) {
strCode = 'with error code ' + code;
} else {
strCode = 'with no error code (manually killed?)';
}
self.logger.error(self.client.name + ' exited ' + strCode);
if (self.onExitCallback) {
self.onExitCallback();
}
});
self.child.on('uncaughtException', (err) => {
self.logger.error('Uncaught ' + self.client.name + ' exception', err);
if (self.onExitCallback) {
self.onExitCallback();
}
});
});
};
Blockchain.prototype.readyCallback = function () {
if (this.onReadyCallback) {
this.onReadyCallback();
}
if (this.config.mineWhenNeeded && !this.isDev) {
this.miner = this.client.getMiner();
}
};
Blockchain.prototype.kill = function () {
if (this.child) {
this.child.kill();
}
};
Blockchain.prototype.checkPathLength = function () {
let _dappPath = dappPath('');
if (_dappPath.length > 66) {
// this.logger.error is captured and sent to the console output regardless of silent setting
this.logger.error("===============================================================================".yellow);
this.logger.error("===========> ".yellow + __('WARNING! ÐApp path length is too long: ').yellow + _dappPath.yellow);
this.logger.error("===========> ".yellow + __('This is known to cause issues with starting geth, please consider reducing your ÐApp path\'s length to 66 characters or less.').yellow);
this.logger.error("===============================================================================".yellow);
}
};
Blockchain.prototype.isClientInstalled = function (callback) {
let versionCmd = this.client.determineVersionCommand();
this.runCommand(versionCmd, {}, (err, stdout, stderr) => {
if (err || !stdout || stderr.indexOf("not found") >= 0 || stdout.indexOf("not found") >= 0) {
return callback(__('Ethereum client bin not found:') + ' ' + this.client.getBinaryPath());
}
const parsedVersion = this.client.parseVersion(stdout);
const supported = this.client.isSupportedVersion(parsedVersion);
if (supported === undefined) {
this.logger.error((__('WARNING! Ethereum client version could not be determined or compared with version range') + ' ' + this.client.versSupported + __(', for best results please use a supported version')).yellow);
} else if (!supported) {
this.logger.error((__('WARNING! Ethereum client version unsupported, for best results please use a version in range') + ' ' + this.client.versSupported).yellow);
}
callback();
});
};
Blockchain.prototype.initDevChain = function(callback) {
const self = this;
const ACCOUNTS_ALREADY_PRESENT = 'accounts_already_present';
// Init the dev chain
self.client.initDevChain(self.config.datadir, (err) => {
if (err) {
return callback(err);
}
const accountsToCreate = self.config.account && self.config.account.numAccounts;
if (!accountsToCreate) return callback();
// Create other accounts
async.waterfall([
function listAccounts(next) {
self.runCommand(self.client.listAccountsCommand(), {}, (err, stdout, _stderr) => {
if (err || stdout === undefined || stdout.indexOf("Fatal") >= 0) {
console.log(__("no accounts found").green);
return next();
}
// List current addresses
self.config.unlockAddressList = self.client.parseListAccountsCommandResultToAddressList(stdout);
// Count current addresses and remove the default account from the count (because password can be different)
let addressCount = self.config.unlockAddressList.length;
if (addressCount < accountsToCreate) {
next(null, accountsToCreate - addressCount);
} else {
next(ACCOUNTS_ALREADY_PRESENT);
}
});
},
function newAccounts(accountsToCreate, next) {
var accountNumber = 0;
async.whilst(
function() {
return accountNumber < accountsToCreate;
},
function(callback) {
accountNumber++;
self.runCommand(self.client.newAccountCommand(), {}, (err, stdout, _stderr) => {
if (err) {
return callback(err, accountNumber);
}
self.config.unlockAddressList.push(self.client.parseNewAccountCommandResultToAddress(stdout));
callback(null, accountNumber);
});
},
function(err) {
next(err);
}
);
}
], (err) => {
if (err && err !== ACCOUNTS_ALREADY_PRESENT) {
console.log(err);
return callback(err);
}
callback();
});
});
};
Blockchain.prototype.initChainAndGetAddress = function (callback) {
const self = this;
let address = null;
const ALREADY_INITIALIZED = 'already';
// ensure datadir exists, bypassing the interactive liabilities prompt.
self.datadir = self.config.datadir;
async.waterfall([
function makeDir(next) {
fs.mkdirp(self.datadir, (err, _result) => {
next(err);
});
},
function listAccounts(next) {
self.runCommand(self.client.listAccountsCommand(), {}, (err, stdout, _stderr) => {
if (err || stdout === undefined || stdout.indexOf("Fatal") >= 0) {
self.logger.info(__("no accounts found").green);
return next();
}
let firstAccountFound = self.client.parseListAccountsCommandResultToAddress(stdout);
if (firstAccountFound === undefined || firstAccountFound === "") {
console.log(__("no accounts found").green);
return next();
}
self.logger.info(__("already initialized").green);
address = firstAccountFound;
next(ALREADY_INITIALIZED);
});
},
function genesisBlock(next) {
//There's no genesis init with Parity. Custom network are set in the chain property at startup
if (!self.config.genesisBlock || self.client.name === constants.blockchain.clients.parity) {
return next();
}
self.logger.info(__("initializing genesis block").green);
self.runCommand(self.client.initGenesisCommmand(), {}, (err, _stdout, _stderr) => {
next(err);
});
},
function newAccount(next) {
self.runCommand(self.client.newAccountCommand(), {}, (err, stdout, _stderr) => {
if (err) {
return next(err);
}
address = self.client.parseNewAccountCommandResultToAddress(stdout);
next();
});
}
], (err) => {
if (err === ALREADY_INITIALIZED) {
err = null;
}
callback(err, address);
});
};
export function BlockchainClient(userConfig, options) {
if ((userConfig === {} || JSON.stringify(userConfig) === '{"enabled":true}') && options.env !== 'development') {
options.logger.info("===> " + __("warning: running default config on a non-development environment"));
}
// if client is not set in preferences, default is geth
if (!userConfig.client) userConfig.client = constants.blockchain.clients.geth;
// if clientName is set, it overrides preferences
if (options.clientName) userConfig.client = options.clientName;
// Choose correct client instance based on clientName
let clientClass;
switch (userConfig.client) {
case constants.blockchain.clients.geth:
clientClass = GethClient;
break;
case constants.blockchain.clients.parity:
clientClass = ParityClient;
break;
default:
console.error(__('Unknown client "%s". Please use one of the following: %s', userConfig.client, Object.keys(constants.blockchain.clients).join(', ')));
process.exit(1);
}
userConfig.isDev = (userConfig.isDev || userConfig.default);
userConfig.env = options.env;
userConfig.onReadyCallback = options.onReadyCallback;
userConfig.onExitCallback = options.onExitCallback;
userConfig.logger = options.logger;
userConfig.certOptions = options.certOptions;
userConfig.isStandalone = options.isStandalone;
return new Blockchain(userConfig, clientClass);
}

View File

@ -1,57 +0,0 @@
import * as i18n from 'embark-i18n';
import { ProcessWrapper } from 'embark-core';
const constants = require('embark-core/constants');
import { BlockchainClient } from './blockchain';
let blockchainProcess;
class BlockchainProcess extends ProcessWrapper {
constructor(options) {
super();
this.blockchainConfig = options.blockchainConfig;
this.client = options.client;
this.env = options.env;
this.isDev = options.isDev;
this.certOptions = options.certOptions;
i18n.setOrDetectLocale(options.locale);
this.blockchainConfig.silent = true;
this.blockchain = BlockchainClient(
this.blockchainConfig,
{
clientName: this.client,
env: this.env,
certOptions: this.certOptions,
onReadyCallback: this.blockchainReady.bind(this),
onExitCallback: this.blockchainExit.bind(this),
logger: console
}
);
this.blockchain.run();
}
blockchainReady() {
blockchainProcess.send({result: constants.blockchain.blockchainReady});
}
blockchainExit() {
// tell our parent process that ethereum client has exited
blockchainProcess.send({result: constants.blockchain.blockchainExit});
}
kill() {
this.blockchain.kill();
}
}
process.on('message', (msg) => {
if (msg === 'exit') {
return blockchainProcess.kill();
}
if (msg.action === constants.blockchain.init) {
blockchainProcess = new BlockchainProcess(msg.options);
return blockchainProcess.send({result: constants.blockchain.initiated});
}
});

View File

@ -1,81 +0,0 @@
import { __ } from 'embark-i18n';
import { ProcessLauncher } from 'embark-core';
import { joinPath } from 'embark-utils';
const constants = require('embark-core/constants');
export class BlockchainProcessLauncher {
constructor (options) {
this.events = options.events;
this.logger = options.logger;
this.normalizeInput = options.normalizeInput;
this.blockchainConfig = options.blockchainConfig;
this.locale = options.locale;
this.isDev = options.isDev;
this.client = options.client;
this.embark = options.embark;
}
processEnded(code) {
this.logger.error(__('Blockchain process ended before the end of this process. Try running blockchain in a separate process using `$ embark blockchain`. Code: %s', code));
}
startBlockchainNode() {
this.logger.info(__('Starting Blockchain node in another process').cyan);
this.blockchainProcess = new ProcessLauncher({
name: 'blockchain',
modulePath: joinPath(__dirname, './blockchainProcess.js'),
logger: this.logger,
events: this.events,
silent: this.logger.logLevel !== 'trace',
exitCallback: this.processEnded.bind(this),
embark: this.embark
});
this.blockchainProcess.send({
action: constants.blockchain.init, options: {
blockchainConfig: this.blockchainConfig,
client: this.client,
env: this.env,
isDev: this.isDev,
locale: this.locale,
certOptions: this.embark.config.webServerConfig.certOptions,
events: this.events
}
});
this.blockchainProcess.once('result', constants.blockchain.blockchainReady, () => {
this.logger.info(__('Blockchain node is ready').cyan);
this.events.emit(constants.blockchain.blockchainReady);
});
this.blockchainProcess.once('result', constants.blockchain.blockchainExit, () => {
// tell everyone that our blockchain process (ie geth) died
this.events.emit(constants.blockchain.blockchainExit);
// then kill off the blockchain process
this.blockchainProcess.kill();
});
this.events.on('logs:ethereum:enable', () => {
this.blockchainProcess.silent = false;
});
this.events.on('logs:ethereum:disable', () => {
this.blockchainProcess.silent = true;
});
this.events.on('exit', () => {
this.blockchainProcess.send('exit');
});
}
stopBlockchainNode(cb) {
if(this.blockchainProcess) {
this.events.once(constants.blockchain.blockchainExit, cb);
this.blockchainProcess.exitCallback = () => {}; // don't show error message as the process was killed on purpose
this.blockchainProcess.send('exit');
}
}
}

View File

@ -1,395 +0,0 @@
import { __ } from 'embark-i18n';
import { dappPath, ipcPath } from 'embark-utils';
const async = require('async');
const {exec, spawn} = require('child_process');
const path = require('path');
const GethMiner = require('./miner');
const semver = require('semver');
const constants = require('embark-core/constants');
const DEFAULTS = {
"BIN": "geth",
"VERSIONS_SUPPORTED": ">=1.8.14",
"NETWORK_TYPE": "custom",
"NETWORK_ID": 1337,
"RPC_API": ['eth', 'web3', 'net', 'debug', 'personal'],
"WS_API": ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub', 'personal'],
"DEV_WS_API": ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub', 'personal'],
"TARGET_GAS_LIMIT": 8000000
};
// TODO: make all of this async
class GethClient {
static get DEFAULTS() {
return DEFAULTS;
}
constructor(options) {
this.config = options && options.hasOwnProperty('config') ? options.config : {};
this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
this.isDev = options && options.hasOwnProperty('isDev') ? options.isDev : (this.env === 'development');
this.name = constants.blockchain.clients.geth;
this.prettyName = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
this.bin = this.config.ethereumClientBin || DEFAULTS.BIN;
this.versSupported = DEFAULTS.VERSIONS_SUPPORTED;
this.httpReady = false;
this.wsReady = !this.config.wsRPC;
}
isReady(data) {
if (data.indexOf('HTTP endpoint opened') > -1) {
this.httpReady = true;
}
if (data.indexOf('WebSocket endpoint opened') > -1) {
this.wsReady = true;
}
return this.httpReady && this.wsReady;
}
/**
* Check if the client needs some sort of 'keep alive' transactions to avoid freezing by inactivity
* @returns {boolean} if keep alive is needed
*/
needKeepAlive() {
// TODO: check version also (geth version < 1.8.15)
if (this.isDev) {
// Trigger regular txs due to a bug in geth (< 1.8.15) and stuck transactions in --dev mode.
return true;
}
return false;
}
commonOptions() {
let config = this.config;
let cmd = [];
cmd.push(this.determineNetworkType(config));
if (config.datadir) {
cmd.push(`--datadir=${config.datadir}`);
}
if (config.syncMode) {
cmd.push("--syncmode=" + config.syncMode);
}
if(this.runAsArchival(config)) {
cmd.push("--gcmode=archive");
}
if (config.account && config.account.password) {
const resolvedPath = path.resolve(dappPath(), config.account.password);
cmd.push(`--password=${resolvedPath}`);
}
if (Number.isInteger(config.verbosity) && config.verbosity >= 0 && config.verbosity <= 5) {
cmd.push("--verbosity=" + config.verbosity);
}
cmd.push(`--ipcpath=${ipcPath('geth.ipc', true)}`);
return cmd;
}
getMiner() {
return new GethMiner({datadir: this.config.datadir});
}
getBinaryPath() {
return this.bin;
}
determineVersionCommand() {
return this.bin + " version";
}
parseVersion(rawVersionOutput) {
let parsed;
const match = rawVersionOutput.match(/Version: (.*)/);
if (match) {
parsed = match[1].trim();
}
return parsed;
}
isSupportedVersion(parsedVersion) {
let test;
try {
let v = semver(parsedVersion);
v = `${v.major}.${v.minor}.${v.patch}`;
test = semver.Range(this.versSupported).test(semver(v));
if (typeof test !== 'boolean') {
test = undefined;
}
} finally {
// eslint-disable-next-line no-unsafe-finally
return test;
}
}
determineNetworkType(config) {
let cmd;
if (config.networkType === 'testnet') {
cmd = "--testnet";
} else if (config.networkType === 'rinkeby') {
cmd = "--rinkeby";
} else if (config.networkType === 'custom') {
cmd = "--networkid=" + config.networkId;
}
return cmd;
}
runAsArchival(config) {
return config.networkId === 1337 || config.archivalMode;
}
initGenesisCommmand() {
let config = this.config;
let cmd = this.bin + " " + this.commonOptions().join(' ');
if (config.genesisBlock) {
cmd += " init \"" + config.genesisBlock + "\" ";
}
return cmd;
}
newAccountCommand() {
if (!(this.config.account && this.config.account.password)) {
console.warn(__('Your blockchain config is missing a password and creating an account may fail. Please consider updating ').yellow + __('config/blockchain > accounts').cyan + __(' then re-run the command').yellow);
}
return this.bin + " " + this.commonOptions().join(' ') + " account new ";
}
parseNewAccountCommandResultToAddress(data = "") {
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
return "";
}
listAccountsCommand() {
return this.bin + " " + this.commonOptions().join(' ') + " account list ";
}
parseListAccountsCommandResultToAddress(data = "") {
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
return "";
}
parseListAccountsCommandResultToAddressList(data = "") {
const regex = RegExp(/{(\w+)}/g);
let match;
const accounts = [];
while ((match = regex.exec(data)) !== null) {
accounts.push('0x' + match[1]);
}
return accounts;
}
parseListAccountsCommandResultToAddressCount(data = "") {
const count = this.parseListAccountsCommandResultToAddressList(data).length;
return (count > 0 ? count : 0);
}
determineRpcOptions(config) {
let cmd = [];
cmd.push("--port=" + config.port);
cmd.push("--rpc");
cmd.push("--rpcport=" + config.rpcPort);
cmd.push("--rpcaddr=" + config.rpcHost);
if (config.rpcCorsDomain) {
if (config.rpcCorsDomain === '*') {
console.warn('==================================');
console.warn(__('rpcCorsDomain set to *'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
}
cmd.push("--rpccorsdomain=" + config.rpcCorsDomain);
} else {
console.warn('==================================');
console.warn(__('warning: cors is not set'));
console.warn('==================================');
}
return cmd;
}
determineWsOptions(config) {
let cmd = [];
if (config.wsRPC) {
cmd.push("--ws");
cmd.push("--wsport=" + config.wsPort);
cmd.push("--wsaddr=" + config.wsHost);
if (config.wsOrigins) {
if (config.wsOrigins === '*') {
console.warn('==================================');
console.warn(__('wsOrigins set to *'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
}
cmd.push("--wsorigins=" + config.wsOrigins);
} else {
console.warn('==================================');
console.warn(__('warning: wsOrigins is not set'));
console.warn('==================================');
}
}
return cmd;
}
initDevChain(datadir, callback) {
exec(this.listAccountsCommand(), {}, (err, stdout, _stderr) => {
const readyTimeout = setTimeout(() => {
this.child.kill();
return cb(__('Geth dev command never returned a developer account'));
}, 10 * 1000);
function cb(err) {
clearTimeout(readyTimeout);
callback(err);
}
if (err || stdout === undefined || stdout.indexOf("Fatal") >= 0) {
return cb(err || stdout);
}
this.config.unlockAddressList = this.parseListAccountsCommandResultToAddressList(stdout);
if (this.config.unlockAddressList.length) {
return cb();
}
// No accounts. We need to run the geth --dev command for it to create the dev account
const args = this.commonOptions();
args.push('--dev');
console.log(__('Creating Geth dev account. Please wait...'));
this.child = spawn(this.bin, args, {cwd: process.cwd()});
this.child.stderr.on('data', async (data) => {
data = data.toString();
if (data.indexOf('Using developer account') > -1) {
this.child.kill();
cb();
}
});
});
}
mainCommand(address, done) {
let self = this;
let config = this.config;
let rpc_api = this.config.rpcApi;
let ws_api = this.config.wsApi;
let args = [];
async.series([
function commonOptions(callback) {
let cmd = self.commonOptions();
args = args.concat(cmd);
callback(null, cmd);
},
function rpcOptions(callback) {
let cmd = self.determineRpcOptions(self.config);
args = args.concat(cmd);
callback(null, cmd);
},
function wsOptions(callback) {
let cmd = self.determineWsOptions(self.config);
args = args.concat(cmd);
callback(null, cmd);
},
function dontGetPeers(callback) {
if (config.nodiscover) {
args.push("--nodiscover");
return callback(null, "--nodiscover");
}
callback(null, "");
},
function vmDebug(callback) {
if (config.vmdebug) {
args.push("--vmdebug");
return callback(null, "--vmdebug");
}
callback(null, "");
},
function maxPeers(callback) {
let cmd = "--maxpeers=" + config.maxpeers;
args.push(cmd);
callback(null, cmd);
},
function mining(callback) {
if (config.mineWhenNeeded || config.mine) {
args.push("--mine");
return callback(null, "--mine");
}
callback("");
},
function bootnodes(callback) {
if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
args.push("--bootnodes=" + config.bootnodes);
return callback(null, "--bootnodes=" + config.bootnodes);
}
callback("");
},
function whisper(callback) {
if (config.whisper) {
rpc_api.push('shh');
if (ws_api.indexOf('shh') === -1) {
ws_api.push('shh');
}
args.push("--shh");
return callback(null, "--shh ");
}
callback("");
},
function rpcApi(callback) {
args.push('--rpcapi=' + rpc_api.join(','));
callback(null, '--rpcapi=' + rpc_api.join(','));
},
function wsApi(callback) {
args.push('--wsapi=' + ws_api.join(','));
callback(null, '--wsapi=' + ws_api.join(','));
},
function accountToUnlock(callback) {
if (self.isDev && self.config.unlockAddressList) {
// The first address is the dev account, that is automatically unlocked by the client using blank password
args.push("--unlock=" + self.config.unlockAddressList.slice(1));
return callback(null, "--unlock=" + self.config.unlockAddressList.slice(1));
}
let accountAddress = "";
if (config.account && config.account.address) {
accountAddress = config.account.address;
} else {
accountAddress = address;
}
if (accountAddress) {
if (!(self.config && self.config.account && self.config.account.password)) {
console.warn(__("\n===== Password needed =====\nPassword for account {{account}} not found. Unlocking this account may fail. Please ensure a password is specified in config/blockchain.js > {{env}} > account > password.\n", {
account: address,
env: self.env
}));
}
args.push("--unlock=" + accountAddress);
return callback(null, "--unlock=" + accountAddress);
}
callback(null, "");
},
function gasLimit(callback) {
if (config.targetGasLimit) {
args.push("--miner.gastarget=" + config.targetGasLimit);
return callback(null, "--miner.gastarget=" + config.targetGasLimit);
}
callback(null, "");
},
function isDev(callback) {
if (self.isDev) {
args.push('--dev');
return callback(null, '--dev');
}
callback(null, '');
}
], function(err) {
if (err) {
throw new Error(err.message);
}
return done(self.bin, args);
});
}
}
module.exports = GethClient;

View File

@ -1,153 +0,0 @@
import { __ } from 'embark-i18n';
const async = require('async');
const { normalizeInput, deconstructUrl } = require('embark-utils');
const constants = require('embark-core/constants');
import { BlockchainProcessLauncher } from './blockchainProcessLauncher';
import {pingEndpoint} from 'embark-utils';
export { BlockchainClient } from './blockchain';
export { Simulator } from './simulator';
export default class BlockchainModule {
constructor(embark, options) {
this.logger = embark.logger;
this.events = embark.events;
this.blockchainConfig = embark.config.blockchainConfig;
this.embark = embark;
this.locale = options.locale;
this.isDev = options.isDev;
this.ipc = options.ipc;
this.client = options.client;
this.blockchainProcess = null;
this.registerBlockchainProcess();
}
registerBlockchainProcess() {
this.events.request('processes:register', 'blockchain', {
launchFn: (cb) => {
this.assertNodeConnection(true, (connected) => {
if (connected) return cb();
this.startBlockchainNode(cb);
this.listenToCommands();
this.registerConsoleCommands();
});
},
stopFn: (cb) => { this.stopBlockchainNode(cb); }
});
if (!this.ipc.isServer()) return;
this.ipc.on('blockchain:node', (_message, cb) => {
cb(null, this.blockchainConfig.endpoint);
});
}
listenToCommands() {
this.events.setCommandHandler('logs:ethereum:enable', (cb) => {
this.events.emit('logs:ethereum:enable');
return cb(null, 'Enabling Geth logs');
});
this.events.setCommandHandler('logs:ethereum:disable', (cb) => {
this.events.emit('logs:ethereum:disable');
return cb(null, 'Disabling Geth logs');
});
}
registerConsoleCommands() {
this.embark.registerConsoleCommand({
matches: ['log blockchain on'],
process: (cmd, callback) => {
this.events.request('logs:ethereum:enable', callback);
}
});
this.embark.registerConsoleCommand({
matches: ['log blockchain off'],
process: (cmd, callback) => {
this.events.request('logs:ethereum:disable', callback);
}
});
}
assertNodeConnection(noLogs, cb) {
if (typeof noLogs === 'function') {
cb = noLogs;
noLogs = false;
}
const self = this;
async.waterfall([
function checkWeb3State(next) {
self.events.request("blockchain:web3:isReady", (connected) => {
if (connected) {
return next(connected);
}
next();
});
},
function _pingEndpoint(next) {
if (!self.blockchainConfig || !self.blockchainConfig.endpoint) {
return next();
}
const {host, port, type, protocol} = deconstructUrl(self.blockchainConfig.endpoint);
pingEndpoint(host, port, type, protocol, self.blockchainConfig.wsOrigins.split(',')[0], next);
}
], function(err) {
if (err === true || err === undefined) {
return cb(true);
}
return cb(false);
});
}
startBlockchainNode(callback) {
const self = this;
this.blockchainProcess = new BlockchainProcessLauncher({
events: self.events,
logger: self.logger,
normalizeInput,
blockchainConfig: self.blockchainConfig,
locale: self.locale,
client: self.client,
isDev: self.isDev,
embark: this.embark
});
this.blockchainProcess.startBlockchainNode();
this.events.once(constants.blockchain.blockchainReady, () => {
this.assertNodeConnection(true, (connected) => {
if (!connected) {
return callback(__('Blockchain process is ready, but still cannot connect to it. Check your host, port and protocol in your contracts config'));
}
this.events.removeListener(constants.blockchain.blockchainExit, callback);
callback();
});
});
this.events.once(constants.blockchain.blockchainExit, callback);
}
stopBlockchainNode(cb) {
const message = __(`The blockchain process has been stopped. It can be restarted by running ${"service blockchain on".bold} in the Embark console.`);
if (this.ipc.isServer()) {
if(!this.ipc.connected) {
this.ipc.connect(() => {
this.ipc.broadcast('process:blockchain:stop');
this.logger.info(message);
});
}
else this.ipc.broadcast('process:blockchain:stop');
}
if(!this.blockchainProcess) {
return cb();
}
this.blockchainProcess.stopBlockchainNode(() => {
this.logger.info(message);
cb();
});
}
}

View File

@ -1,318 +0,0 @@
const async = require('async');
const NetcatClient = require('netcat/client');
import { ipcPath } from 'embark-utils';
//Constants
const minerStart = 'miner_start';
const minerStop = 'miner_stop';
const getHashRate = 'miner_getHashrate';
const getCoinbase = 'eth_coinbase';
const getBalance = 'eth_getBalance';
const newBlockFilter = 'eth_newBlockFilter';
const pendingBlockFilter = 'eth_newPendingTransactionFilter';
const getChanges = 'eth_getFilterChanges';
const getBlockCount = 'eth_getBlockTransactionCountByNumber';
class GethMiner {
constructor(options) {
const self = this;
// TODO: Find a way to load mining config from YML.
// In the meantime, just set an empty config object
this.config = {};
this.datadir = options.datadir;
self.interval = null;
self.callback = null;
self.started = null;
self.commandQueue = async.queue((task, callback) => {
self.callback = callback;
self.client.send(JSON.stringify({"jsonrpc": "2.0", "method": task.method, "params": task.params || [], "id": 1}));
}, 1);
const defaults = {
interval_ms: 15000,
initial_ether: 15000000000000000000,
mine_pending_txns: true,
mine_periodically: false,
mine_normally: false,
threads: 1
};
for (let key in defaults) {
if (this.config[key] === undefined) {
this.config[key] = defaults[key];
}
}
this.client = new NetcatClient();
this.client.unixSocket(ipcPath('geth.ipc', true))
.enc('utf8')
.connect()
.on('data', (response) => {
try {
response = JSON.parse(response);
} catch (e) {
console.error(e);
return;
}
if (self.callback) {
self.callback(response.error, response.result);
}
});
if (this.config.mine_normally) {
this.startMiner();
return;
}
self.stopMiner(() => {
self.fundAccount(function (err) {
if (err) {
console.error(err);
return;
}
if (self.config.mine_periodically) self.start_periodic_mining();
if (self.config.mine_pending_txns) self.start_transaction_mining();
});
});
}
sendCommand(method, params, callback) {
if (typeof params === 'function') {
callback = params;
params = [];
}
if (!callback) {
callback = function () {
};
}
this.commandQueue.push({method, params: params || []}, callback);
}
startMiner(callback) {
if (this.started) {
if (callback) {
callback();
}
return;
}
this.started = true;
this.sendCommand(minerStart, callback);
}
stopMiner(callback) {
if (!this.started) {
if (callback) {
callback();
}
return;
}
this.started = false;
this.sendCommand(minerStop, callback);
}
getCoinbase(callback) {
if (this.coinbase) {
return callback(null, this.coinbase);
}
this.sendCommand(getCoinbase, (err, result) => {
if (err) {
return callback(err);
}
this.coinbase = result;
if (!this.coinbase) {
return callback('Failed getting coinbase account');
}
callback(null, this.coinbase);
});
}
accountFunded(callback) {
const self = this;
self.getCoinbase((err, coinbase) => {
if (err) {
return callback(err);
}
self.sendCommand(getBalance, [coinbase, 'latest'], (err, result) => {
if (err) {
return callback(err);
}
callback(null, parseInt(result, 16) >= self.config.initial_ether);
});
});
}
watchBlocks(filterCommand, callback, delay) {
const self = this;
self.sendCommand(filterCommand, (err, filterId) => {
if (err) {
return callback(err);
}
self.interval = setInterval(() => {
self.sendCommand(getChanges, [filterId], (err, changes) => {
if (err) {
console.error(err);
return;
}
if (!changes || !changes.length) {
return;
}
callback(null, changes);
});
}, delay || 1000);
});
}
mineUntilFunded(callback) {
const self = this;
this.startMiner();
self.watchBlocks(newBlockFilter, (err) => {
if (err) {
console.error(err);
return;
}
self.accountFunded((err, funded) => {
if (funded) {
clearTimeout(self.interval);
self.stopMiner();
callback();
}
});
});
}
fundAccount(callback) {
const self = this;
self.accountFunded((err, funded) => {
if (err) {
return callback(err);
}
if (funded) {
return callback();
}
console.log("== Funding account");
self.mineUntilFunded(callback);
});
}
pendingTransactions(callback) {
const self = this;
self.sendCommand(getBlockCount, ['pending'], (err, hexCount) => {
if (err) {
return callback(err);
}
callback(null, parseInt(hexCount, 16));
});
}
start_periodic_mining() {
const self = this;
const WAIT = 'wait';
let last_mined_ms = Date.now();
let timeout_set = false;
let next_block_in_ms;
self.startMiner();
self.watchBlocks(newBlockFilter, (err) => {
if (err) {
console.error(err);
return;
}
if (timeout_set) {
return;
}
async.waterfall([
function checkPendingTransactions(next) {
if (!self.config.mine_pending_txns) {
return next();
}
self.pendingTransactions((err, count) => {
if (err) {
return next(err);
}
if (count) {
return next(WAIT);
}
next();
});
},
function stopMiner(next) {
timeout_set = true;
const now = Date.now();
const ms_since_block = now - last_mined_ms;
last_mined_ms = now;
if (ms_since_block > self.config.interval_ms) {
next_block_in_ms = 0;
} else {
next_block_in_ms = (self.config.interval_ms - ms_since_block);
}
self.stopMiner();
console.log("== Looking for next block in " + next_block_in_ms + "ms");
next();
},
function startAfterTimeout(next) {
setTimeout(function () {
console.log("== Looking for next block");
timeout_set = false;
self.startMiner();
next();
}, next_block_in_ms);
}
], (err) => {
if (err === WAIT) {
return;
}
if (err) {
console.error(err);
}
});
});
}
start_transaction_mining() {
const self = this;
const pendingTrasactionsMessage = "== Pending transactions! Looking for next block...";
self.watchBlocks(pendingBlockFilter, (err) => {
if (err) {
console.error(err);
return;
}
self.sendCommand(getHashRate, (err, result) => {
if (result > 0) return;
console.log(pendingTrasactionsMessage);
self.startMiner();
});
}, 2000);
if (self.config.mine_periodically) return;
self.watchBlocks(newBlockFilter, (err) => {
if (err) {
console.error(err);
return;
}
self.pendingTransactions((err, count) => {
if (err) {
console.error(err);
return;
}
if (!count) {
console.log("== No transactions left. Stopping miner...");
self.stopMiner();
} else {
console.log(pendingTrasactionsMessage);
self.startMiner();
}
});
}, 2000);
}
}
module.exports = GethMiner;

View File

@ -1,407 +0,0 @@
import { __ } from 'embark-i18n';
import { dappPath } from 'embark-utils';
import * as fs from 'fs-extra';
const async = require('async');
const path = require('path');
const os = require('os');
const semver = require('semver');
const constants = require('embark-core/constants');
const DEFAULTS = {
"BIN": "parity",
"VERSIONS_SUPPORTED": ">=2.0.0",
"NETWORK_TYPE": "dev",
"NETWORK_ID": 17,
"RPC_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub"],
"WS_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub"],
"DEV_WS_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub", "personal"],
"TARGET_GAS_LIMIT": 8000000,
"DEV_ACCOUNT": "0x00a329c0648769a73afac7f9381e08fb43dbea72",
"DEV_WALLET": {
"id": "d9460e00-6895-8f58-f40c-bb57aebe6c00",
"version": 3,
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": {"iv": "74245f453143f9d06a095c6e6e309d5d"},
"ciphertext": "2fa611c4aa66452ef81bd1bd288f9d1ed14edf61aa68fc518093f97c791cf719",
"kdf": "pbkdf2",
"kdfparams": {"c": 10240, "dklen": 32, "prf": "hmac-sha256", "salt": "73b74e437a1144eb9a775e196f450a23ab415ce2c17083c225ddbb725f279b98"},
"mac": "f5882ae121e4597bd133136bf15dcbcc1bb2417a25ad205041a50c59def812a8"
},
"address": "00a329c0648769a73afac7f9381e08fb43dbea72",
"name": "Development Account",
"meta": "{\"description\":\"Never use this account outside of development chain!\",\"passwordHint\":\"Password is empty string\"}"
}
};
const safePush = function(set, value) {
if (set.indexOf(value) === -1) {
set.push(value);
}
};
class ParityClient {
static get DEFAULTS() {
return DEFAULTS;
}
constructor(options) {
this.config = options && options.hasOwnProperty('config') ? options.config : {};
this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
this.isDev = options && options.hasOwnProperty('isDev') ? options.isDev : (this.env === 'development');
this.name = constants.blockchain.clients.parity;
this.prettyName = "Parity-Ethereum (https://github.com/paritytech/parity-ethereum)";
this.bin = this.config.ethereumClientBin || DEFAULTS.BIN;
this.versSupported = DEFAULTS.VERSIONS_SUPPORTED;
}
isReady(data) {
return data.indexOf('Public node URL') > -1;
}
/**
* Check if the client needs some sort of 'keep alive' transactions to avoid freezing by inactivity
* @returns {boolean} if keep alive is needed
*/
needKeepAlive() {
return false;
}
commonOptions() {
let config = this.config;
let cmd = [];
cmd.push(this.determineNetworkType(config));
if (config.networkId) {
cmd.push(`--network-id=${config.networkId}`);
}
if (config.datadir) {
cmd.push(`--base-path=${config.datadir}`);
}
if (config.syncMode === 'light') {
cmd.push("--light");
} else if (config.syncMode === 'fast') {
cmd.push("--pruning=fast");
} else if (config.syncMode === 'full') {
cmd.push("--pruning=archive");
}
// In dev mode we store all users passwords in the devPassword file, so Parity can unlock all users from the start
if (this.isDev) cmd.push(`--password=${config.account.devPassword}`);
else if (config.account && config.account.password) {
cmd.push(`--password=${config.account.password}`);
}
if (Number.isInteger(config.verbosity) && config.verbosity >= 0 && config.verbosity <= 5) {
switch (config.verbosity) {
case 0: // No option to silent Parity, go to less verbose
case 1:
cmd.push("--logging=error");
break;
case 2:
cmd.push("--logging=warn");
break;
case 3:
cmd.push("--logging=info");
break;
case 4: // Debug is the max verbosity for Parity
case 5:
cmd.push("--logging=debug");
break;
default:
cmd.push("--logging=info");
break;
}
}
if(this.runAsArchival(config)) {
cmd.push("--pruning=archive");
}
return cmd;
}
getMiner() {
console.warn(__("Miner requested, but Parity does not embed a miner! Use Geth or install ethminer (https://github.com/ethereum-mining/ethminer)").yellow);
return;
}
getBinaryPath() {
return this.bin;
}
determineVersionCommand() {
return this.bin + " --version";
}
parseVersion(rawVersionOutput) {
let parsed;
const match = rawVersionOutput.match(/version Parity(?:-Ethereum)?\/(.*?)\//);
if (match) {
parsed = match[1].trim();
}
return parsed;
}
runAsArchival(config) {
return config.networkId === 1337 || config.archivalMode;
}
isSupportedVersion(parsedVersion) {
let test;
try {
let v = semver(parsedVersion);
v = `${v.major}.${v.minor}.${v.patch}`;
test = semver.Range(this.versSupported).test(semver(v));
if (typeof test !== 'boolean') {
test = undefined;
}
} finally {
// eslint-disable-next-line no-unsafe-finally
return test;
}
}
determineNetworkType(config) {
if (this.isDev) {
return "--chain=dev";
}
if (config.networkType === 'rinkeby') {
console.warn(__('Parity does not support the Rinkeby PoA network, switching to Kovan PoA network'));
config.networkType = 'kovan';
} else if (config.networkType === 'testnet') {
console.warn(__('Parity "testnet" corresponds to Kovan network, switching to Ropsten to be compliant with Geth parameters'));
config.networkType = "ropsten";
}
if (config.genesisBlock) {
config.networkType = config.genesisBlock;
}
return "--chain=" + config.networkType;
}
newAccountCommand() {
return this.bin + " " + this.commonOptions().join(' ') + " account new ";
}
parseNewAccountCommandResultToAddress(data = "") {
return data.replace(/^\n|\n$/g, "");
}
listAccountsCommand() {
return this.bin + " " + this.commonOptions().join(' ') + " account list ";
}
parseListAccountsCommandResultToAddress(data = "") {
return data.replace(/^\n|\n$/g, "").split('\n')[0];
}
parseListAccountsCommandResultToAddressList(data = "") {
const list = data.split('\n');
return list.filter(acc => acc);
}
parseListAccountsCommandResultToAddressCount(data = "") {
const count = this.parseListAccountsCommandResultToAddressList(data).length;
return (count > 0 ? count : 0);
}
determineRpcOptions(config) {
let cmd = [];
cmd.push("--port=" + config.port);
cmd.push("--jsonrpc-port=" + config.rpcPort);
cmd.push("--jsonrpc-interface=" + (config.rpcHost === 'localhost' ? 'local' : config.rpcHost));
if (config.rpcCorsDomain) {
if (config.rpcCorsDomain === '*') {
console.warn('==================================');
console.warn(__('rpcCorsDomain set to "all"'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
}
cmd.push("--jsonrpc-cors=" + (config.rpcCorsDomain === '*' ? 'all' : config.rpcCorsDomain));
} else {
console.warn('==================================');
console.warn(__('warning: cors is not set'));
console.warn('==================================');
}
cmd.push("--jsonrpc-hosts=all");
return cmd;
}
determineWsOptions(config) {
let cmd = [];
if (config.wsRPC) {
cmd.push("--ws-port=" + config.wsPort);
cmd.push("--ws-interface=" + (config.wsHost === 'localhost' ? 'local' : config.wsHost));
if (config.wsOrigins) {
const origins = config.wsOrigins.split(',');
if (origins.includes('*') || origins.includes("all")) {
console.warn('==================================');
console.warn(__('wsOrigins set to "all"'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
cmd.push("--ws-origins=all");
} else {
cmd.push("--ws-origins=" + config.wsOrigins);
}
} else {
console.warn('==================================');
console.warn(__('warning: wsOrigins is not set'));
console.warn('==================================');
}
cmd.push("--ws-hosts=all");
}
return cmd;
}
initDevChain(datadir, callback) {
// Parity requires specific initialization also for the dev chain
const self = this;
const keysDataDir = datadir + '/keys/DevelopmentChain';
async.waterfall([
function makeDir(next) {
fs.mkdirp(keysDataDir, (err, _result) => {
next(err);
});
},
function createDevAccount(next) {
self.createDevAccount(keysDataDir, next);
},
function mkDevPasswordDir(next) {
fs.mkdirp(path.dirname(self.config.account.devPassword), (err, _result) => {
next(err);
});
},
function getText(next) {
if (!self.config.account.password) {
return next(null, os.EOL + 'dev_password');
}
fs.readFile(dappPath(self.config.account.password), {encoding: 'utf8'}, (err, content) => {
next(err, os.EOL + content);
});
},
function updatePasswordFile(passwordList, next) {
fs.writeFile(self.config.account.devPassword, passwordList, next);
}
], (err) => {
callback(err);
});
}
createDevAccount(keysDataDir, cb) {
const devAccountWallet = keysDataDir + '/dev.wallet';
fs.writeFile(devAccountWallet, JSON.stringify(DEFAULTS.DEV_WALLET), function(err) {
if (err) {
return cb(err);
}
cb();
});
}
mainCommand(address, done) {
let self = this;
let config = this.config;
let rpc_api = this.config.rpcApi;
let ws_api = this.config.wsApi;
let args = [];
async.series([
function commonOptions(callback) {
let cmd = self.commonOptions();
args = args.concat(cmd);
callback(null, cmd);
},
function rpcOptions(callback) {
let cmd = self.determineRpcOptions(self.config);
args = args.concat(cmd);
callback(null, cmd);
},
function wsOptions(callback) {
let cmd = self.determineWsOptions(self.config);
args = args.concat(cmd);
callback(null, cmd);
},
function dontGetPeers(callback) {
if (config.nodiscover) {
args.push("--no-discovery");
return callback(null, "--no-discovery");
}
callback(null, "");
},
function vmDebug(callback) {
if (config.vmdebug) {
args.push("--tracing on");
return callback(null, "--tracing on");
}
callback(null, "");
},
function maxPeers(callback) {
let cmd = "--max-peers=" + config.maxpeers;
args.push(cmd);
callback(null, cmd);
},
function bootnodes(callback) {
if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
args.push("--bootnodes=" + config.bootnodes);
return callback(null, "--bootnodes=" + config.bootnodes);
}
callback("");
},
function whisper(callback) {
if (config.whisper) {
safePush(rpc_api, 'shh');
safePush(rpc_api, 'shh_pubsub');
safePush(ws_api, 'shh');
safePush(ws_api, 'shh_pubsub');
args.push("--whisper");
return callback(null, "--whisper");
}
callback("");
},
function rpcApi(callback) {
args.push('--jsonrpc-apis=' + rpc_api.join(','));
callback(null, '--jsonrpc-apis=' + rpc_api.join(','));
},
function wsApi(callback) {
args.push('--ws-apis=' + ws_api.join(','));
callback(null, '--ws-apis=' + ws_api.join(','));
},
function accountToUnlock(callback) {
if (self.isDev) {
let unlockAddressList = self.config.unlockAddressList ? self.config.unlockAddressList : DEFAULTS.DEV_ACCOUNT;
args.push("--unlock=" + unlockAddressList);
return callback(null, "--unlock=" + unlockAddressList);
}
let accountAddress = "";
if (config.account && config.account.address) {
accountAddress = config.account.address;
} else {
accountAddress = address;
}
if (accountAddress && !self.isDev) {
args.push("--unlock=" + accountAddress);
return callback(null, "--unlock=" + accountAddress);
}
callback(null, "");
},
function gasLimit(callback) {
if (config.targetGasLimit) {
args.push("--gas-floor-target=" + config.targetGasLimit);
return callback(null, "--gas-floor-target=" + config.targetGasLimit);
}
// Default Parity gas limit is 4700000: let's set to the geth default
args.push("--gas-floor-target=" + DEFAULTS.TARGET_GAS_LIMIT);
return callback(null, "--gas-floor-target=" + DEFAULTS.TARGET_GAS_LIMIT);
}
], function(err) {
if (err) {
throw new Error(err.message);
}
return done(self.bin, args);
});
}
}
module.exports = ParityClient;

View File

@ -1,88 +0,0 @@
const path = require('path');
const pkgUp = require('pkg-up');
let shelljs = require('shelljs');
import {AccountParser, dappPath, defaultHost, dockerHostSwap, embarkPath, deconstructUrl} from 'embark-utils';
export class Simulator {
constructor(options) {
this.blockchainConfig = options.blockchainConfig;
this.contractsConfig = options.contractsConfig;
this.logger = options.logger;
}
/*eslint complexity: ["error", 26]*/
run(options) {
let cmds = [];
let {host, port} = deconstructUrl(this.blockchainConfig.endpoint);
host = (dockerHostSwap(options.host || host) || defaultHost);
port = (options.port || port || 8545);
port = parseInt(port, 10);
cmds.push("-p " + port);
cmds.push("-h " + host);
cmds.push("-l " + (options.gasLimit || this.blockchainConfig.targetGasLimit || 8000000));
// adding mnemonic only if it is defined in the blockchainConfig or options
let mnemonicAccount = this.blockchainConfig.accounts ? this.blockchainConfig.accounts.find(acc => acc.mnemonic) : {};
mnemonicAccount = mnemonicAccount || {};
const simulatorMnemonic = mnemonicAccount.mnemonic || options.simulatorMnemonic;
if (simulatorMnemonic) {
cmds.push("--mnemonic \"" + (simulatorMnemonic) + "\"");
}
cmds.push("-a " + (options.numAccounts || mnemonicAccount.numAddresses || 10));
cmds.push("-e " + (options.defaultBalance || mnemonicAccount.balance || 100));
// as ganache-cli documentation explains, the simulatorAccounts configuration overrides a mnemonic
let simulatorAccounts = this.blockchainConfig.simulatorAccounts || options.simulatorAccounts;
if (simulatorAccounts && simulatorAccounts.length > 0) {
let web3 = new (require('web3'))();
let parsedAccounts;
try {
parsedAccounts = AccountParser.parseAccountsConfig(simulatorAccounts, web3, dappPath(), this.logger);
} catch (e) {
this.logger.error(e.message);
process.exit(1);
}
parsedAccounts.forEach((account) => {
let cmd = '--account="' + account.privateKey + ',' + account.hexBalance + '"';
cmds.push(cmd);
});
}
// adding blocktime only if it is defined in the blockchainConfig or options
let simulatorBlocktime = this.blockchainConfig.simulatorBlocktime || options.simulatorBlocktime;
if (simulatorBlocktime) {
cmds.push("-b \"" + (simulatorBlocktime) + "\"");
}
// Setting up network id for simulator from blockchainConfig or options.
// Otherwise ganache-cli would make random network id.
let networkId = this.blockchainConfig.networkId || options.networkId;
if (networkId) { // Don't handle networkId=="0" because it is not a valid networkId for ganache-cli.
cmds.push("--networkId " + networkId);
}
this.runCommand(cmds, host, port);
}
runCommand(cmds) {
const ganache_main = require.resolve('ganache-cli', {paths: [embarkPath('node_modules')]});
const ganache_json = pkgUp.sync(path.dirname(ganache_main));
const ganache_root = path.dirname(ganache_json);
const ganache_bin = require(ganache_json).bin;
let ganache;
if (typeof ganache_bin === 'string') {
ganache = path.join(ganache_root, ganache_bin);
} else {
ganache = path.join(ganache_root, ganache_bin['ganache-cli']);
}
const programName = 'ganache-cli';
const program = ganache;
console.log(`running: ${programName} ${cmds.join(' ')}`);
shelljs.exec(`node ${program} ${cmds.join(' ')}`, {async: true});
}
}

View File

@ -1,4 +0,0 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
}

View File

@ -1,3 +0,0 @@
{
"extends": "../../tslint.json"
}

View File

@ -1,4 +0,0 @@
engine-strict = true
package-lock = false
save-exact = true
scripts-prepend-node-path = true

View File

@ -1,70 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.1.1](https://github.com/embark-framework/embark/compare/v4.1.0...v4.1.1) (2019-08-28)
**Note:** Version bump only for package embark-code-generator
# [4.1.0](https://github.com/embark-framework/embark/compare/v4.1.0-beta.6...v4.1.0) (2019-08-12)
**Note:** Version bump only for package embark-code-generator
# [4.1.0-beta.6](https://github.com/embark-framework/embark/compare/v4.1.0-beta.5...v4.1.0-beta.6) (2019-08-09)
**Note:** Version bump only for package embark-code-generator
# [4.1.0-beta.5](https://github.com/embark-framework/embark/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2019-07-10)
### Bug Fixes
* **@embark/code-generator:** use plugins for contract generation ([c87d7da](https://github.com/embark-framework/embark/commit/c87d7da))
# [4.1.0-beta.4](https://github.com/embark-framework/embark/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2019-06-27)
### Bug Fixes
* alleviate races re: embarkjs by introducing Plugin#addGeneratedCode and related refactors ([fc4faa8](https://github.com/embark-framework/embark/commit/fc4faa8))
# [4.1.0-beta.3](https://github.com/embark-framework/embark/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2019-06-07)
**Note:** Version bump only for package embark-code-generator
# [4.1.0-beta.2](https://github.com/embark-framework/embark/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2019-05-22)
**Note:** Version bump only for package embark-code-generator
# [4.1.0-beta.1](https://github.com/embark-framework/embark/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2019-05-15)
**Note:** Version bump only for package embark-code-generator

View File

@ -1,6 +0,0 @@
# `embark-code-generator`
Embark code generator
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -1,73 +0,0 @@
{
"name": "embark-code-generator",
"version": "4.1.1",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Embark code generator",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/embark-code-generator#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
"dapps",
"ethereum",
"ipfs",
"serverless",
"solc",
"solidity"
],
"files": [
"dist"
],
"license": "MIT",
"repository": {
"directory": "packages/embark-code-generator",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"scripts": {
"build": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --root-mode upward --source-maps --copy-files",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "npm-run-all lint:*",
"lint:js": "eslint src/",
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
"package": "npm pack",
"// qa": "npm-run-all lint typecheck build package",
"qa": "npm-run-all lint build package",
"reset": "npx rimraf dist embark-*.tgz package",
"start": "npm run watch",
"// typecheck": "tsc",
"watch": "run-p watch:*",
"watch:build": "npm run build -- --verbose --watch",
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
},
"eslintConfig": {
"extends": "../../.eslintrc.json"
},
"dependencies": {
"@babel/core": "7.2.2",
"@babel/runtime-corejs2": "7.3.1",
"async": "2.6.1",
"ejs": "2.6.1",
"embark-core": "^4.1.1",
"embark-i18n": "^4.1.1",
"embark-utils": "^4.1.1",
"fs-extra": "7.0.1"
},
"devDependencies": {
"@babel/cli": "7.2.3",
"@babel/core": "7.2.2",
"cross-env": "5.2.0",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"rimraf": "3.0.0",
"tslint": "5.16.0",
"typescript": "3.4.5"
},
"engines": {
"node": ">=8.12.0 <12.0.0",
"npm": ">=6.4.1",
"yarn": ">=1.12.3"
}
}

View File

@ -1,8 +0,0 @@
if (typeof WebSocket !== 'undefined') {
const ws = new WebSocket(`${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.hostname}:${location.port}`);
ws.addEventListener('message', (evt) => {
if (evt.data === 'outputDone') {
location.reload(true);
}
});
}

View File

@ -1,7 +0,0 @@
var whenEnvIsLoaded = function(cb) {
if (typeof document !== 'undefined' && document !== null && !/comp|inter|loaded/.test(document.readyState)) {
document.addEventListener('DOMContentLoaded', cb);
} else {
cb();
}
}

View File

@ -1,7 +0,0 @@
whenEnvIsLoaded(function(){
__mainContext.__loadManagerInstance.doFirst(function(done) {
<%- block %>
});
EmbarkJS.environment = "<%- environment %>";
});

View File

@ -1 +0,0 @@
__mainContext.<%- className %> = new EmbarkJS.Blockchain.Contract({abi: <%- abi %>, address: <%- contractAddress %>, code: '<%- contract.code %>', gasEstimates: <%- gasEstimates %>});

View File

@ -1,3 +0,0 @@
whenEnvIsLoaded(function() {
<%- block %>
});

View File

@ -1,3 +0,0 @@
__mainContext.__loadManagerInstance.execWhenReady(function() {
<%- block %>
});

View File

@ -1,4 +0,0 @@
__mainContext.__LoadManager = function() { this.list = []; this.done = false; this.err = null; }
__mainContext.__LoadManager.prototype.execWhenReady = function(cb) { if (this.done) { cb(this.err); } else { this.list.push(cb) } }
__mainContext.__LoadManager.prototype.doFirst = function(todo) { var self = this; todo(function(err) { self.done = true; self.err = err; self.list.map((x) => x.apply(x, [self.err])) }) }
__mainContext.__loadManagerInstance = new __mainContext.__LoadManager();

View File

@ -1,3 +0,0 @@
var __mainContext = __mainContext || (
this ? this : typeof self !== 'undefined' ? self : void 0
);

View File

@ -1,9 +0,0 @@
<%- className %>Abi = <%- abi %>;
<%- className %> = new web3.eth.Contract(<%- className %>Abi);
<%- className %>.options.address = '<%- contract.deployedAddress %>';
<%- className %>.address = '<%- contract.deployedAddress %>';
<%- className %>.options.from = web3.eth.defaultAccount;
<% if (gasLimit != false) { %>
<%- className %>.options.gas = <%- gasLimit %>;
<%- className %>.options.gasLimit = <%- gasLimit %>;
<% } %>

View File

@ -1,544 +0,0 @@
import { __ } from 'embark-i18n';
import { dappPath, embarkPath, joinPath, toForwardSlashes } from 'embark-utils';
import * as fs from 'fs-extra';
import { transform } from "@babel/core";
const async = require('async');
const constants = require('embark-core/constants');
const path = require('path');
require('ejs');
const Templates = {
vanilla_contract: require('./code_templates/vanilla-contract.js.ejs'),
embarkjs_contract: require('./code_templates/embarkjs-contract.js.ejs'),
exec_when_ready: require('./code_templates/exec-when-ready.js.ejs'),
load_manager: require('./code_templates/load-manager.js.ejs'),
define_when_env_loaded: require('./code_templates/define-when-env-loaded.js.ejs'),
main_context: require('./code_templates/main-context.js.ejs'),
do_when_loaded: require('./code_templates/do-when-loaded.js.ejs'),
exec_when_env_loaded: require('./code_templates/exec-when-env-loaded.js.ejs')
};
class CodeGenerator {
constructor(embark, options) {
this.ready = false;
this.blockchainConfig = embark.config.blockchainConfig || {};
this.embarkConfig = embark.config.embarkConfig;
this.dappConfigs = {};
this.logger = embark.logger;
this.rpcHost = this.blockchainConfig.rpcHost || '';
this.rpcPort = this.blockchainConfig.rpcPort || '';
this.contractsConfig = embark.config.contractsConfig || {};
this.config = embark.config;
this.env = options.env || 'development';
this.plugins = options.plugins;
this.events = embark.events;
this.listenToCommands();
this.ready = true;
this.events.emit('code-generator:ready');
}
listenToCommands() {
this.events.on('config:load:contracts', this.generateContractConfig.bind(this));
this.events.on('config:load:storage', this.generateStorageConfig.bind(this));
this.events.on('config:load:communication', this.generateCommunicationConfig.bind(this));
this.events.setCommandHandler('code', (cb) => {
this.events.request("contracts:list", (_err, contractsList) => {
let embarkJSABI = this.generateABI(contractsList, {useEmbarkJS: true});
let contractsJSON = this.generateContractsJSON(contractsList);
cb(embarkJSABI, contractsJSON);
});
});
this.events.setCommandHandler('code-generator:contract', (contractName, cb) => {
this.events.request('contracts:contract', contractName, (contract) => {
this.buildContractJS(contract, cb);
});
});
this.events.setCommandHandler('code-generator:contract:vanilla', (contract, gasLimit, cb) => {
cb(this.generateContractCode(contract, gasLimit));
});
this.events.setCommandHandler('code-generator:contract:custom', (contract, cb) => {
const customCode = this.generateCustomContractCode(contract);
if (!customCode) {
// Fallback to generate code from vanilla contract generator.
//
// TODO: can be moved into a afterDeploy event
// just need to figure out the gasLimit coupling issue
return cb(this.generateContractCode(contract, contract._gasLimit || false));
}
cb(customCode);
});
this.events.setCommandHandler('code-generator:embarkjs:provider-code', (cb) => {
cb(this.getEmbarkJsProviderCode());
});
this.events.setCommandHandler('code-generator:embarkjs:set-provider-code', (cb) => {
cb(this.getSetProviderCode());
});
this.events.setCommandHandler('code-generator:embarkjs:init-provider-code', (cb) => {
cb(this.getInitProviderCode());
});
this.events.setCommandHandler('code-generator:symlink:generate', (...args) => {
this.generateSymlink(...args);
});
this.events.setCommandHandler("code-generator:embarkjs:build", (cb) => {
this.buildEmbarkJS(cb);
});
this.events.setCommandHandler('code-generator:ready', (cb) => {
if (this.ready) {
return cb();
}
this.events.once('code-generator:ready', cb);
});
}
getSetProviderCode() {
let code = "\n";
code += this.generateCommunicationInitialization(true);
code += this.generateStorageInitialization(true);
code += this.generateNamesInitialization(true);
return code;
}
generateContracts(contractsList, useEmbarkJS, isDeployment, useLoader) {
let self = this;
let result = "\n";
let contractsPlugins;
if (useLoader === false) {
for (let contract of contractsList) {
let abi = JSON.stringify(contract.abiDefinition);
result += Templates.vanilla_contract({className: contract.className, abi: abi, contract: contract, gasLimit: constants.codeGenerator.gasLimit});
}
return result;
}
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
return "";
}
if (this.plugins) {
contractsPlugins = this.plugins.getPluginsFor('contractGeneration');
}
if (this.plugins && contractsPlugins.length > 0) {
contractsPlugins.forEach(function (plugin) {
result += plugin.generateContracts({contracts: contractsList});
});
} else {
for (let contract of contractsList) {
let abi = JSON.stringify(contract.abiDefinition);
let gasEstimates = JSON.stringify(contract.gasEstimates);
let block = "";
if (useEmbarkJS) {
let contractAddress = contract.deployedAddress ? ("'" + contract.deployedAddress + "'") : "undefined";
block += Templates.embarkjs_contract({className: contract.className, abi: abi, contract: contract, contractAddress: contractAddress, gasEstimates: gasEstimates});
} else {
block += Templates.vanilla_contract({className: contract.className, abi: abi, contract: contract, gasLimit: (isDeployment ? constants.codeGenerator.gasLimit : false)});
}
result += Templates.exec_when_ready({block: block});
}
}
return result;
}
checkIfNeedsUpdate(file, newOutput, callback) {
fs.readFile(file, (err, content) => {
if (err) {
return callback(null, true);
}
callback(null, content.toString() !== newOutput);
});
}
generateContractConfig(contractConfig, callback = () => {}) {
this.dappConfigs.blockchain = {
dappConnection: contractConfig.dappConnection,
dappAutoEnable: contractConfig.dappAutoEnable,
warnIfMetamask: this.blockchainConfig.isDev,
blockchainClient: this.blockchainConfig.client
};
this.generateArtifact(this.dappConfigs.blockchain, constants.dappArtifacts.blockchain, constants.dappArtifacts.dir, (err, path, _updated) => {
callback(err, path);
});
}
generateStorageConfig(storageConfig) {
this.dappConfigs.storage = {
dappConnection: storageConfig.dappConnection
};
this.generateArtifact(this.dappConfigs.storage, constants.dappArtifacts.storage, constants.dappArtifacts.dir);
}
generateCommunicationConfig(communicationConfig) {
this.dappConfigs.communication = {
connection: communicationConfig.connection
};
this.generateArtifact(this.dappConfigs.communication, constants.dappArtifacts.communication, constants.dappArtifacts.dir);
}
generateArtifact(artifactInput, fileName, dirName, cb = () => {}) {
const dir = joinPath(this.embarkConfig.generationDir, dirName);
const filePath = joinPath(dir, fileName);
if (typeof artifactInput !== 'string') {
artifactInput = JSON.stringify(artifactInput, null, 2);
}
async.waterfall([
(next) => {
fs.mkdirp(dir, next);
},
(_dir, next) => {
this.checkIfNeedsUpdate(filePath, artifactInput, next);
},
(needsUpdate, next) => {
if (!needsUpdate) {
return next(null, false);
}
fs.writeFile(filePath, artifactInput, (err) => {
next(err, true);
});
}
], (err, updated) => {
if (err) {
this.logger.error(err.message || err);
}
cb(err, filePath, updated);
});
}
generateContractCode(contract, gasLimit) {
let abi = JSON.stringify(contract.abiDefinition);
let block = "";
block += Templates.vanilla_contract({className: contract.className, abi: abi, contract: contract, gasLimit: gasLimit});
return block;
}
generateCustomContractCode(contract) {
const customContractGeneratorPlugin = this.plugins.getPluginsFor('customContractGeneration').splice(-1)[0];
if (!customContractGeneratorPlugin) {
return null;
}
return customContractGeneratorPlugin.generateCustomContractCode(contract);
}
generateNamesInitialization(useEmbarkJS) {
if (!useEmbarkJS || this.config.namesystemConfig === {}) return "";
let result = "\n";
result += Templates.define_when_env_loaded();
result += this._getInitCode('names', this.config.namesystemConfig);
return result;
}
generateStorageInitialization(useEmbarkJS) {
if (!useEmbarkJS || this.config.storageConfig === {}) return "";
let result = "\n";
result += Templates.define_when_env_loaded();
result += this._getInitCode('storage', this.config.storageConfig);
return result;
}
generateCommunicationInitialization(useEmbarkJS) {
if (!useEmbarkJS || this.config.communicationConfig === {}) return "";
let result = "\n";
result += Templates.define_when_env_loaded();
result += this._getInitCode('communication', this.config.communicationConfig);
return result;
}
_getInitCode(codeType, config) {
let result = "";
let pluginsWithCode = this.plugins.getPluginsFor('initCode');
for (let plugin of pluginsWithCode) {
let initCodes = plugin.embarkjs_init_code[codeType] || [];
for (let initCode of initCodes) {
let [block, shouldInit] = initCode;
if (shouldInit.call(plugin, config)) {
result += Templates.exec_when_env_loaded({block: block});
}
}
}
return result;
}
generateABI(contractsList, options) {
let result = "";
result += this.generateContracts(contractsList, options.useEmbarkJS, options.deployment, true);
result += this.generateStorageInitialization(options.useEmbarkJS);
result += this.generateCommunicationInitialization(options.useEmbarkJS);
result += this.generateNamesInitialization(options.useEmbarkJS);
return result;
}
generateContractJSON(className, contract) {
let contractJSON = {};
contractJSON.contract_name = className;
contractJSON.address = contract.deployedAddress;
contractJSON.code = contract.code;
contractJSON.runtime_bytecode = contract.runtimeBytecode;
contractJSON.real_runtime_bytecode = contract.realRuntimeBytecode;
contractJSON.swarm_hash = contract.swarmHash;
contractJSON.gas_estimates = contract.gasEstimates;
contractJSON.function_hashes = contract.functionHashes;
contractJSON.abi = contract.abiDefinition;
return contractJSON;
}
generateContractsJSON(contractsList) {
let contracts = {};
for (let contract of contractsList) {
contracts[contract.className] = this.generateContractJSON(contract.className, contract);
}
return contracts;
}
buildEmbarkJS(cb) {
const self = this;
let embarkjsCode = '';
let code = "/* eslint-disable */";
async.waterfall([
// TODO: here due to a race condition when running embark build
function generateConfig(next) {
self.events.request("config:contractsConfig", (contractsConfig) => {
self.generateContractConfig(contractsConfig, () => {
next();
});
});
},
function getEmbarkJsLocation(next) {
self.events.request('version:downloadIfNeeded', 'embarkjs', (err, location) => {
if (err) {
self.logger.error(__('Error downloading EmbarkJS'));
return next(err);
}
next(null, location);
});
},
function generateSymlink(location, next) {
self.generateSymlink(location, 'embarkjs', (err, symlinkDest) => {
if (err) {
self.logger.error(__('Error creating a symlink to EmbarkJS'));
return next(err);
}
embarkjsCode += `\nconst EmbarkJS = require("${symlinkDest}").default || require("${symlinkDest}");`;
embarkjsCode += `\nEmbarkJS.environment = '${self.env}';`;
embarkjsCode += "\nglobal.EmbarkJS = EmbarkJS;";
code += "\n" + embarkjsCode + "\n";
next();
});
},
function addCodeFromDependencies(next) {
async.eachSeries(
self.plugins.getPluginsFor('generatedCode'),
(plugin, callback) => {
async.eachSeries(
plugin.generated_code,
(codeCall, callback) => {
codeCall((err, generatedCode, packageName, location) => {
if (err) return callback(err);
self.generateSymlink(location, packageName, (err, _symlinkDest) => {
if (err) {
self.logger.error(__(`Error creating a symlink to ${packageName}`));
return callback(err);
}
code += generatedCode;
callback();
});
});
},
(err) => { callback(err); }
);
},
(err) => { next(err); }
);
},
function getJSCode(next) {
code += self.getEmbarkJsProviderCode();
code += self.generateCommunicationInitialization(true);
code += self.generateStorageInitialization(true);
code += self.generateNamesInitialization(true);
code += self.getReloadPageCode();
code += "\nexport default EmbarkJS;";
code += "\nif (typeof module !== 'undefined' && module.exports) {" +
"\n\tmodule.exports = EmbarkJS;" +
"\n}";
code += '\n/* eslint-enable */\n';
next();
},
function writeFile(next) {
self.generateArtifact(code, constants.dappArtifacts.embarkjs, '', next);
},
function transformCode(artifactPath, updated, next) {
if (!updated) {
return next();
}
transform(code, {
cwd: embarkPath(),
"presets": [
[
"@babel/preset-env", {
"targets": {
"node": "8.11.3"
}
}
]
]
}, (err, result) => {
if (err) {
return next(err);
}
self.generateArtifact(result.code, constants.dappArtifacts.embarkjsnode, '', next);
});
}
], function(_err, _result) {
cb();
});
}
getReloadPageCode() {
return this.env === 'development' ? fs.readFileSync(path.join(__dirname, '/code/reload-on-change.js'), 'utf8') : '';
}
getEmbarkJsProviderCode() {
return this.plugins.getPluginsFor('embarkjsCode').reduce((code, plugin) => (
code += plugin.embarkjs_code.join('\n')
), '');
}
getInitProviderCode() {
const codeTypes = {
blockchain: this.config.blockchainConfig || {},
communication: this.config.communicationConfig || {},
names: this.config.namesystemConfig || {},
storage: this.config.storageConfig || {}
};
return this.plugins.getPluginsFor("initConsoleCode").reduce((acc, plugin) => {
Object.keys(codeTypes).forEach((codeTypeName) => {
(plugin.embarkjs_init_console_code[codeTypeName] || []).forEach((initCode) => {
const [block, shouldInit] = initCode;
if (shouldInit.call(plugin, codeTypes[codeTypeName])) {
acc += block;
}
});
});
return acc;
}, "");
}
buildContractJS(contract, cb) {
const contractName = contract.className;
if (this.plugins) {
const contractsPlugins = this.plugins.getPluginsFor('contractGeneration');
if (contractsPlugins.length > 0) {
let result = '';
contractsPlugins.forEach(function (plugin) {
result += plugin.generateContracts({contracts: {[contractName]: contract}});
});
return this.generateArtifact(result, contractName + '.js', constants.dappArtifacts.contractsJs, (err, path, _updated) => {
cb(err, path);
});
}
}
const contractJSON = this.generateContractJSON(contractName, contract);
const contractCode = `
"use strict";
const isNode = (typeof process !== 'undefined' && process.versions && process.versions.node);
const lib = isNode ? '../embarkjs.node' : '../embarkjs';
const EmbarkJSNode = isNode && require('../embarkjs.node');
let EmbarkJSBrowser;
try {
EmbarkJSBrowser = require('../embarkjs').default;
} catch(e) {};
const EmbarkJS = isNode ? EmbarkJSNode : EmbarkJSBrowser;
let ${contractName}JSONConfig = ${JSON.stringify(contractJSON)};
let ${contractName} = new EmbarkJS.Blockchain.Contract(${contractName}JSONConfig);
module.exports = ${contractName};
`.trim().replace(/^[\t\s]+/gm, '');
this.generateArtifact(contractCode, contractName + '.js', constants.dappArtifacts.contractsJs, (err, path, _updated) => {
cb(err, path);
});
}
generateSymlink(target, name, callback) {
async.waterfall([
// Make directory
next => {
const symlinkDir = dappPath(this.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir);
fs.mkdirp(symlinkDir, (err) => {
if (err) {
return next(err);
}
next(null, toForwardSlashes(joinPath(symlinkDir, name)));
});
},
// Remove old symlink because they are not overwritable
(symlinkDest, next) => {
fs.remove(symlinkDest, (err) => {
if (err) {
return next(err);
}
next(null, symlinkDest);
});
},
// Make target a directory as files don't work on Windows
(symlinkDest, next) => {
fs.stat(target, (err, stats) => {
if (err) {
return next(err);
}
let finalTarget = target;
if (stats.isFile()) {
finalTarget = path.dirname(target);
}
next(null, symlinkDest, finalTarget);
});
},
(symlinkDest, finalTarget, next) => {
fs.symlink(finalTarget, symlinkDest, 'junction', (err) => {
if (err) {
return next(err);
}
next(null, symlinkDest);
});
}
], callback);
}
}
module.exports = CodeGenerator;

View File

@ -1,4 +0,0 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
}

View File

@ -1,3 +0,0 @@
{
"extends": "../../tslint.json"
}

View File

@ -93,10 +93,7 @@
"embark-accounts-manager": "^4.1.1",
"embark-api": "^4.1.1",
"embark-authenticator": "^4.1.1",
"embark-blockchain-connector": "^4.1.1",
"embark-blockchain-listener": "^4.1.1",
"embark-blockchain-process": "^4.1.1",
"embark-code-generator": "^4.1.1",
"embark-code-runner": "^4.1.1",
"embark-compiler": "^4.1.1",
"embark-console": "^4.1.1",

View File

@ -15,7 +15,6 @@ class Cmd {
this.demo();
this.build();
this.run();
this.run2();
this.console();
this.blockchain();
this.simulator();
@ -170,42 +169,6 @@ class Cmd {
});
}
run2() {
program
.command('run2 [environment]')
.option('-p, --port [port]', __('port to run the dev webserver (default: %s)', '8000'))
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
.option('-b, --host [host]', __('host to run the dev webserver (default: %s)', 'localhost'))
.option('--noserver', __('disable the development webserver'))
.option('--nodashboard', __('simple mode, disables the dashboard'))
.option('--nobrowser', __('prevent the development webserver from automatically opening a web browser'))
.option('--no-color', __('no colors in case it\'s needed for compatbility purposes'))
.option('--logfile [logfile]', __('filename to output logs (default: %s)', 'none'))
.option('--loglevel [loglevel]', __('level of logging to display') + ' ["error", "warn", "info", "debug", "trace"]', /^(error|warn|info|debug|trace)$/i, 'debug')
.option('--locale [locale]', __('language to use (default: en)'))
.option('--pipeline [pipeline]', __('webpack config to use (default: development)'))
.option('--no-single-use-auth-token', __('disable the single use of token in cockpit'))
.description(__('run dapp (default: %s)', 'development'))
.action(function(env, options) {
setOrDetectLocale(options.locale);
embark.run2({
env: env || 'development',
serverPort: options.port,
serverHost: options.host,
client: options.client,
locale: options.locale,
runWebserver: !options.noserver ? null : false,
useDashboard: !options.nodashboard,
logFile: options.logfile,
logLevel: options.loglevel,
webpackConfigName: options.pipeline || 'development',
openBrowser: !options.nobrowser ? null : false,
singleUseAuthToken: options.singleUseAuthToken
});
});
}
console() {
program
.command('console [environment]')

View File

@ -1,4 +1,3 @@
import {Simulator} from 'embark-blockchain-process';
import {__} from 'embark-i18n';
import {dappPath, embarkPath} from 'embark-utils';
import findUp from 'find-up';
@ -71,16 +70,15 @@ class EmbarkController {
});
});
}
simulator(options) {
this.context = options.context || [constants.contexts.simulator, constants.contexts.blockchain];
let simulator = new Simulator({
blockchainConfig: this.config.blockchainConfig,
contractsConfig: this.config.contractsConfig,
logger: this.logger,
fs
});
simulator.run(options);
simulator(options) {
// this.context = options.context || [constants.contexts.simulator, constants.contexts.blockchain];
// let simulator = new Simulator({
// blockchainConfig: this.config.blockchainConfig,
// contractsConfig: this.config.contractsConfig,
// logger: this.logger,
// fs
// });
// simulator.run(options);
}
generateTemplate(templateName, destinationFolder, name, url) {
@ -94,8 +92,8 @@ class EmbarkController {
templateGenerator.generate(destinationFolder, name);
}
run2(options) {
const self = this;
run(options) {
let self = this;
self.context = options.context || [constants.contexts.run, constants.contexts.build];
let Dashboard = require('./dashboard/dashboard.js');
@ -230,137 +228,6 @@ class EmbarkController {
});
}
run(options) {
let self = this;
self.context = options.context || [constants.contexts.run, constants.contexts.build];
let Dashboard = require('./dashboard/dashboard.js');
const webServerConfig = {};
if (options.runWebserver !== null && options.runWebserver !== undefined) {
webServerConfig.enabled = options.runWebserver;
}
if (options.serverHost !== null && options.serverHost !== undefined) {
webServerConfig.host = options.serverHost;
}
if (options.serverPort !== null && options.serverPort !== undefined) {
webServerConfig.port = options.serverPort;
}
if (options.openBrowser !== null && options.openBrowser !== undefined) {
webServerConfig.openBrowser = options.openBrowser;
}
const Engine = require('../lib/core/engine.js');
const engine = new Engine({
env: options.env,
client: options.client,
locale: options.locale,
version: this.version,
embarkConfig: options.embarkConfig || 'embark.json',
logFile: options.logFile,
logLevel: options.logLevel,
context: self.context,
useDashboard: options.useDashboard,
webServerConfig: webServerConfig,
webpackConfigName: options.webpackConfigName,
singleUseAuthToken: options.singleUseAuthToken,
ipcRole: 'server'
});
async.waterfall([
function initEngine(callback) {
engine.init({}, () => {
engine.startService("embarkListener");
if (!options.useDashboard) {
engine.logger.info('========================'.bold.green);
engine.logger.info((__('Welcome to Embark') + ' ' + engine.version).yellow.bold);
engine.logger.info('========================'.bold.green);
}
callback();
});
},
function (callback) {
engine.startService("libraryManager").installAll((err) => callback(err ? err : null));
},
function (callback) {
let pluginList = engine.plugins.listPlugins();
if (pluginList.length > 0) {
engine.logger.info(__("loaded plugins") + ": " + pluginList.join(", "));
}
engine.startService("web3");
engine.startService("processManager");
engine.startService("coreProcess");
engine.startService("blockchainListener");
engine.startService("serviceMonitor");
engine.startService("codeRunner");
engine.startService("pipeline");
engine.startService("deployment");
engine.startService("storage");
engine.startService("codeGenerator");
engine.startService("console");
engine.startService("cockpit");
engine.startService("pluginCommand");
engine.startService("blockchain");
engine.events.on('check:backOnline:Ethereum', function () {
engine.logger.info(__('Ethereum node detected') + '..');
engine.config.reloadConfig();
engine.events.request('deploy:contracts', function (err) {
if (err) {
return engine.logger.error(err.message || err);
}
engine.logger.info(__('Deployment Done'));
});
});
engine.events.on('outputDone', function () {
engine.logger.info((__("Looking for documentation? You can find it at") + " ").cyan + "http://embark.status.im/docs/".green.underline + ".".cyan);
engine.logger.info(__("Ready").underline);
engine.events.emit("status", __("Ready").green);
});
if (webServerConfig.enabled !== false) {
engine.startService("webServer");
}
engine.startService("fileWatcher");
engine.startEngine(() => {
callback();
});
},
function startDashboard(callback) {
if (!options.useDashboard) {
return callback();
}
let dashboard = new Dashboard({
events: engine.events,
logger: engine.logger,
plugins: engine.plugins,
version: self.version,
env: engine.env,
ipc: engine.ipc
});
dashboard.start(function () {
engine.logger.info(__('dashboard start'));
callback();
});
}
], function (err, _result) {
if (err) {
engine.logger.error(err.message);
engine.logger.info(err.stack);
process.exit(1);
} else {
engine.events.emit('firstDeploymentDone');
}
});
}
build(options) {
this.context = options.context || [constants.contexts.build];

View File

@ -1,10 +1,10 @@
import {ProcessManager, IPC} from 'embark-core';
const EMBARK_PROCESS_NAME = 'embark';
const utils = require('../utils/utils');
const Logger = require('embark-logger');
const EMBARK_PROCESS_NAME = 'embark';
class Engine {
constructor(options) {
this.env = options.env;
@ -210,16 +210,7 @@ class Engine {
}
contractsComponents(_options) {
// this.registerModulePackage('embark-blockchain-connector', {
// isDev: this.isDev,
// locale: this.locale,
// plugins: this.plugins,
// web3: options.web3,
// wait: options.wait
// });
this.registerModule('ethereum-blockchain-client');
// this.registerModule('web3', { plugins: this.plugins });
this.registerModulePackage('embark-web3');
this.registerModulePackage('embark-accounts-manager');
this.registerModulePackage('embark-specialconfigs', {plugins: this.plugins});
@ -240,161 +231,6 @@ class Engine {
this.registerModulePackage('embark-ens');
}
// ================
// ================
// ================
// To be removed
// ================
startService(serviceName, _options) {
let options = _options || {};
let services = {
"serviceMonitor": this.serviceMonitor,
"pipeline": this.pipelineService,
"cockpit": this.cockpitService,
"codeRunner": this.codeRunnerService,
"codeGenerator": this.codeGeneratorService,
"compiler": this.setupCompilerAndContractsManagerService,
"deployment": this.deploymentService,
"fileWatcher": this.fileWatchService,
"webServer": this.webServerService,
"console": this.console,
"web3": this.web3Service,
"libraryManager": this.libraryManagerService,
"processManager": this.processManagerService,
"storage": this.storageService,
"pluginCommand": this.pluginCommandService,
"graph": this.graphService,
"testRunner": this.testRunnerService,
"codeCoverage": this.codeCoverageService,
"scaffolding": this.scaffoldingService,
"coreProcess": this.coreProcessService,
"processApi": this.processApiService,
"blockchainListener": this.blockchainListenerService,
"blockchain": this.blockchainComponents
};
let service = services[serviceName];
if (!service) {
throw new Error("unknown service: " + serviceName);
}
// need to be careful with circular references due to passing the web3 object
//this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")");
return service.apply(this, [options]);
}
embarkListenerService(_options) {
this.registerModulePackage('embark-listener');
}
blockchainListenerService(_options) {
this.registerModulePackage('embark-blockchain-listener', {
ipc: this.ipc
});
}
coreProcessService(_options) {
this.registerModulePackage('embark-core/process', {
events: this.events
});
}
processManagerService(_options) {
this.processManager = new ProcessManager({
events: this.events,
logger: this.logger,
plugins: this.plugins
});
}
graphService(_options) {
this.registerModulePackage('embark-graph');
}
scaffoldingService(_options) {
this.registerModulePackage('embark-scaffolding', {plugins: this.plugins});
}
serviceMonitor() {
const ServicesMonitor = require('./services_monitor.js');
this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger, plugins: this.plugins});
this.servicesMonitor.addCheck('Embark', function (cb) {
return cb({name: 'Embark ' + self.version, status: 'on'});
}, 0);
this.servicesMonitor.startMonitor();
}
pluginCommandService() {
this.registerModulePackage('embark-plugin-cmd', {embarkConfigFile: this.embarkConfig, embarkConfig: this.config.embarkConfig, packageFile: 'package.json'});
}
codeRunnerService(_options) {
this.registerModulePackage('embark-code-runner', {
ipc: this.ipc
});
}
codeGeneratorService(_options) {
return;
// let self = this;
//
// this.registerModulePackage('embark-code-generator', {plugins: self.plugins, env: self.env});
//
// const generateCode = function (modifiedAssets) {
// // self.events.request("module:storage:onReady", () => {
// self.events.request("code-generator:embarkjs:build", () => {
// self.events.emit('code-generator-ready', modifiedAssets);
// });
// // });
// };
// const cargo = async.cargo((tasks, callback) => {
// const modifiedAssets = tasks.map(task => task.modifiedAsset).filter(asset => asset); // filter null elements
// generateCode(modifiedAssets);
// self.events.once('outputDone', callback);
// });
// const addToCargo = function (modifiedAsset) {
// cargo.push({modifiedAsset});
// };
//
// this.events.on('contractsDeployed', addToCargo);
// this.events.on('blockchainDisabled', addToCargo);
// this.events.on('asset-changed', addToCargo);
}
setupCompilerAndContractsManagerService(options) {
this.registerModulePackage('embark-compiler', {plugins: this.plugins, isCoverage: options.isCoverage});
this.registerModulePackage('embark-solidity', {ipc: this.ipc, useDashboard: this.useDashboard});
this.registerModulePackage('embark-vyper');
this.registerModulePackage('embark-contracts-manager', {plugins: this.plugins, compileOnceOnly: options.compileOnceOnly});
}
deploymentService(options) {
let self = this;
this.setupCompilerAndContractsManagerService(options);
this.registerModulePackage('embark-solidity', {ipc: self.ipc, useDashboard: this.useDashboard});
this.registerModulePackage('embark-vyper');
this.registerModulePackage('embark-profiler');
this.registerModulePackage('embark-deploy-tracker', {trackContracts: options.trackContracts});
this.registerModulePackage('embark-specialconfigs');
this.registerModulePackage('embark-console-listener', {ipc: self.ipc});
this.registerModulePackage('embark-deployment', {plugins: this.plugins, onlyCompile: options.onlyCompile});
this.registerModulePackage('embark-transaction-tracker');
this.registerModulePackage('embark-debugger');
}
fileWatchService() {
this.registerModulePackage('embark-watcher');
this.events.request('watcher:start');
}
cockpitService() {
this.registerModulePackage('embark-authenticator', {singleUseAuthToken: this.singleUseAuthToken});
this.registerModulePackage('embark-api', {plugins: this.plugins});
}
cockpitModules() {
this.registerModulePackage('embark-authenticator', {singleUseAuthToken: this.singleUseAuthToken});
@ -403,65 +239,6 @@ class Engine {
this.events.request('process:logs:register', {processName: EMBARK_PROCESS_NAME, eventName: "log", silent: false, alwaysAlreadyLogged: true});
}
webServerService() {
this.registerModulePackage('embark-webserver');
}
storageService(_options) {
this.registerModulePackage('embark-storage', {plugins: this.plugins});
this.registerModulePackage('embark-ipfs');
this.registerModulePackage('embark-swarm');
// this.registerModulePackage('embark-swarm');
// this.events.setCommandHandler("module:storage:reset", (cb) => {
// async.parallel([
// (paraCb) => {
// this.events.request("module:ipfs:reset", paraCb);
// },
// (paraCb) => {
// this.events.request("module:swarm:reset", paraCb);
// },
// (paraCb) => {
// this.events.request("module:storageJS:reset", paraCb);
// }
// ], cb);
// });
}
web3Service(options) {
this.registerModulePackage('embark-web3', {plugins: this.plugins});
this.registerModulePackage('embark-blockchain-process', {
client: this.client,
locale: this.locale,
isDev: this.isDev,
ipc: this.ipc
});
this.registerModulePackage('embark-blockchain-connector', {
isDev: this.isDev,
locale: this.locale,
plugins: this.plugins,
web3: options.web3,
wait: options.wait
});
this.registerModulePackage('embark-whisper', {plugins: this.plugins});
this.registerModule('web3', {plugins: this.plugins});
}
libraryManagerService(_options) {
return this.registerModulePackage('embark-library-manager', {useDashboard: this.useDashboard});
}
codeCoverageService(_options) {
this.registerModulePackage('embark-coverage');
}
testRunnerService(options) {
this.registerModulePackage('embark-test-runner', Object.assign(options, {ipc: this.ipc}));
}
}
module.exports = Engine;

View File

@ -1,144 +0,0 @@
/*globals describe, it*/
import { BlockchainClient } from 'embark-blockchain-process';
const constants = require('embark-core/constants');
import { dappPath, defaultHost} from 'embark-utils';
const path = require('path');
const fs = require('../lib/core/fs.js');
const assert = require('assert');
describe('embark.Blockchain', function() {
describe('#initializer', function() {
describe('with empty config', function() {
it('should have a default config', function(done) {
const blockchain = new BlockchainClient({}, { fs });
const expectedConfig = {
networkType: 'custom',
genesisBlock: false,
client: 'geth',
ethereumClientBin: 'geth',
datadir: dappPath(".embark/development/datadir"),
mineWhenNeeded: false,
rpcHost: defaultHost,
rpcPort: 8545,
rpcApi: ['eth', 'web3', 'net', 'debug', "personal"],
rpcCorsDomain: "http://localhost:8000",
networkId: 1337,
port: 30303,
nodiscover: false,
maxpeers: 25,
mine: false,
vmdebug: false,
whisper: true,
bootnodes: "",
wsApi: ["eth", "web3", "net", "shh", "debug", "pubsub", "personal"],
wsHost: defaultHost,
wsOrigins: "http://localhost:8000",
wsPort: 8546,
wsRPC: true,
targetGasLimit: 8000000,
syncMode: undefined,
verbosity: undefined,
proxy: undefined,
silent: undefined
};
expectedConfig.account = {devPassword: path.join(expectedConfig.datadir, "devPassword")};
assert.deepEqual(blockchain.config, expectedConfig);
done();
});
});
describe('with config', function() {
it('should take config params', function(done) {
let config = {
networkType: 'livenet',
genesisBlock: 'foo/bar/genesis.json',
client: 'parity',
ethereumClientBin: 'parity',
datadir: '/foo/datadir/',
mineWhenNeeded: true,
rpcHost: defaultHost,
rpcPort: 12345,
rpcApi: ['eth', 'web3', 'net', 'debug', "personal"],
rpcCorsDomain: true,
networkId: 1,
port: 123456,
nodiscover: true,
maxpeers: 25,
mine: true,
vmdebug: false,
whisper: false,
bootnodes: "",
wsApi: ["eth", "web3", "net", "shh", "debug", "personal"],
wsHost: defaultHost,
wsOrigins: false,
wsPort: 12346,
wsRPC: true,
targetGasLimit: false,
syncMode: undefined,
verbosity: undefined,
proxy: true,
accounts: [
{
nodeAccounts: true,
numAddresses: "2",
password: "config/development/devpassword"
},
{
mnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
numAddresses: "3"
}
]
};
let blockchain = new BlockchainClient(config, { fs });
let expectedConfig = {
networkType: 'livenet',
genesisBlock: 'foo/bar/genesis.json',
client: 'parity',
ethereumClientBin: 'parity',
datadir: '/foo/datadir/',
mineWhenNeeded: true,
rpcHost: defaultHost,
rpcPort: 12345,
rpcApi: ['eth', 'web3', 'net', 'debug', 'personal'],
rpcCorsDomain: true,
networkId: 1,
port: 123456,
nodiscover: true,
maxpeers: 25,
mine: true,
vmdebug: false,
whisper: false,
bootnodes: "",
wsApi: ["eth", "web3", "net", "shh", "debug", "personal"],
wsHost: defaultHost,
wsOrigins: false,
wsPort: 12346,
wsRPC: true,
targetGasLimit: false,
syncMode: undefined,
verbosity: undefined,
proxy: true,
silent: undefined,
account: {
numAccounts: "2",
devPassword: path.normalize("/foo/datadir/devPassword"),
password: "config/development/devpassword",
balance: undefined
}
};
// We check also proxy's ports because proxy is set to true
expectedConfig.wsPort += constants.blockchain.servicePortOnProxy;
expectedConfig.rpcPort += constants.blockchain.servicePortOnProxy;
assert.deepEqual(blockchain.config, expectedConfig);
done();
});
});
});
});

View File

@ -1,66 +0,0 @@
/*globals describe, it*/
let CodeGenerator = require('embark-code-generator');
let assert = require('assert');
function replaceCRLF(string) {
return string.replace(/\r\n/g, '\n');
}
// TODO: instead 'eval' the code with a fake web3 object
// and check the generate code interacts as expected
describe('embark.CodeGenerator', function() {
this.timeout(0);
describe('#generateContracts', function() {
let contracts = [
{
className: 'SimpleStorage',
abiDefinition: [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}],
gasEstimates: 12000,
deployedAddress: "0x123",
code: '12345'
},
{
className: 'Foo',
abiDefinition: [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}],
gasEstimates: 12000,
deployedAddress: "0x124",
code: '123456'
}
];
const currentSolcVersion = require('../../package.json').dependencies.solc;
const TestEvents = {
request: (cmd, cb) => {
cb(currentSolcVersion);
},
setCommandHandler: () => {
},
on: () => {},
emit: () => {}
};
let generator = new CodeGenerator({config: {blockchainConfig: {}}, events: TestEvents}, {});
describe('with EmbarkJS', function() {
let withEmbarkJS = true;
it('should generate contract code', function() {
var contractCode = "\n__mainContext.__loadManagerInstance.execWhenReady(function() {\n __mainContext.SimpleStorage = new EmbarkJS.Blockchain.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x123', code: '12345', gasEstimates: 12000});\n\n});\n__mainContext.__loadManagerInstance.execWhenReady(function() {\n __mainContext.Foo = new EmbarkJS.Blockchain.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x124', code: '123456', gasEstimates: 12000});\n\n});\n";
assert.strictEqual(replaceCRLF(generator.generateContracts(contracts, withEmbarkJS)), contractCode);
});
});
describe('with default interface', function() {
let withEmbarkJS = false;
it('should generate contract code', function() {
var contractCode = "\n__mainContext.__loadManagerInstance.execWhenReady(function() {\n SimpleStorageAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nSimpleStorage = new web3.eth.Contract(SimpleStorageAbi);\nSimpleStorage.options.address = '0x123';\nSimpleStorage.address = '0x123';\nSimpleStorage.options.from = web3.eth.defaultAccount;\n\n\n});\n__mainContext.__loadManagerInstance.execWhenReady(function() {\n FooAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nFoo = new web3.eth.Contract(FooAbi);\nFoo.options.address = '0x124';\nFoo.address = '0x124';\nFoo.options.from = web3.eth.defaultAccount;\n\n\n});\n";
assert.strictEqual(replaceCRLF(generator.generateContracts(contracts, withEmbarkJS)), contractCode);
});
});
});
//describe('#generateABI', function() {
//});
});

View File

@ -1,158 +0,0 @@
/*globals describe, it, before*/
const {
expect
} = require('chai');
const sinon = require('sinon');
import { IPC } from 'embark-core';
let fs = require('../lib/core/fs');
const { Proxy } = require('embark-blockchain-process');
const constants = require('embark-core/constants');
describe('embark.Proxy', function () {
let ipc, proxy, ipcRequests;
before(function () {
ipc = new IPC({
ipcRole: 'none',
fs: fs
});
ipcRequests = [];
ipc.connected = true;
sinon.stub(ipc, 'request').callsFake((...args) => {
ipcRequests.push(args);
});
proxy = new Proxy(ipc);
});
describe('#trackRequest', function () {
it('should handle eth_sendTransaction', function (done) {
const to = "to";
const data = "data";
proxy.trackRequest({ws: true, data: {
id: 1,
method: constants.blockchain.transactionMethods.eth_sendTransaction,
params: [{
to: to,
data: data
}]
}});
expect(proxy.commList[1]).to.deep.equal({
type: 'contract-log',
address: to,
data: data
});
done();
});
it('should handle eth_sendRawTransaction', function (done) {
const to = "0x2e6242a07ea1c4e79ecc5c69a2dccae19878a280";
const data = "0x60fe47b1000000000000000000000000000000000000000000000000000000000000115c";
proxy.trackRequest({ws: true, data: {
id: 1,
method: constants.blockchain.transactionMethods.eth_sendRawTransaction,
params: ["0xf8852701826857942e6242a07ea1c4e79ecc5c69a2dccae19878a28080a460fe47b1000000000000000000000000000000000000000000000000000000000000115c820a96a04d6e3cbb86d80a75cd51da02bf8f0cc9893d64ca7956ce21b350cc143aa8a023a05878a850e4e7810d08093add07df405298280fdd901ecbabb74e73422cb5e0b0"]
}});
expect(proxy.commList[1]).to.deep.equal({
type: 'contract-log',
address: to,
data: data
});
done();
});
});
describe('#trackResponse', function () {
describe('when the response is a transaction', function () {
before(function () {
proxy.trackRequest({ws: true, data: {
id: 1,
method: constants.blockchain.transactionMethods.eth_sendTransaction,
params: [{to: "to", data: "data" }]
}});
});
it('should populate the transaction when it is a known id', function (done) {
proxy.trackResponse({
id: 1,
result: 1
});
expect(proxy.transactions[1]).to.deep.equal({
commListId: 1
});
done();
});
it('should not populate the transaction when it is a unknown id', function (done) {
proxy.trackResponse({
id: 2
});
expect(proxy.transactions[2]).to.be.equal(undefined);
done();
});
});
describe('when the response is a receipt', function () {
it('should make an ipc call', function (done) {
proxy.trackRequest({ws: true, data: {
id: 3,
method: constants.blockchain.transactionMethods.eth_sendTransaction,
params: [{
to: "to",
data: "data"
}]
}});
proxy.trackResponse({
id: 3,
result: {
to: "to",
data: "data"
}
});
proxy.trackRequest({ws: true, data: {
id: 4,
method: constants.blockchain.transactionMethods.eth_getTransactionReceipt,
params: [{
to: "to",
data: "data"
}]
}});
expect(proxy.receipts[4]).to.be.equal(3);
proxy.trackResponse({
id: 4,
result: {
blockNumber: 666,
gasUsed: 122,
status: 'ok'
}
});
expect(ipcRequests[0]).to.deep.equal([
"log", {
"address": "to",
"blockNumber": 666,
"data": "data",
"gasUsed": 122,
"status": "ok",
"transactionHash": {
"data": "data",
"to": "to"
},
"type": "contract-log"
}
]);
done();
});
});
});
});