Merged in merge conflicts from remote

This commit is contained in:
emizzle 2018-05-22 12:16:13 +10:00
commit 46e040f861
21 changed files with 616 additions and 403 deletions

View File

@ -125,8 +125,9 @@ Blockchain.prototype.initChainAndGetAddress = function() {
}; };
var BlockchainClient = function(blockchainConfig, client, env, isDev) { var BlockchainClient = function(blockchainConfig, client, env, isDev) {
// TODO add other clients at some point
if (client === 'geth') { if (client === 'geth') {
return new Blockchain({blockchainConfig: blockchainConfig, client: GethCommands, env: env, isDev}); return new Blockchain({blockchainConfig, client: GethCommands, env, isDev});
} else { } else {
throw new Error('unknown client'); throw new Error('unknown client');
} }

View File

@ -1,4 +1,4 @@
let async = require('async'); const async = require('async');
// TODO: make all of this async // TODO: make all of this async
class GethCommands { class GethCommands {

View File

@ -0,0 +1,73 @@
const bip39 = require("bip39");
const hdkey = require('ethereumjs-wallet/hdkey');
const fs = require('../core/fs');
class AccountParser {
static parseAccountsConfig(accountsConfig, web3, logger) {
let accounts = [];
if (accountsConfig && accountsConfig.length) {
accountsConfig.forEach(accountConfig => {
const account = AccountParser.getAccount(accountConfig, web3, logger);
if (!account) {
return;
}
if (Array.isArray(account)) {
accounts = accounts.concat(account);
return;
}
accounts.push(account);
});
}
return accounts;
}
static getAccount(accountConfig, web3, logger) {
if (!logger) {
logger = console;
}
if (accountConfig.privateKey) {
if (!accountConfig.privateKey.startsWith('0x')) {
accountConfig.privateKey = '0x' + accountConfig.privateKey;
}
if (!web3.utils.isHexStrict(accountConfig.privateKey)) {
logger.warn(`Private key ending with ${accountConfig.privateKey.substr(accountConfig.privateKey.length - 5)} is not a HEX string`);
return null;
}
return web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey);
}
if (accountConfig.privateKeyFile) {
let fileContent = fs.readFileSync(fs.dappPath(accountConfig.privateKeyFile)).toString();
fileContent = fileContent.trim().split(/[,;]/);
return fileContent.map((key, index) => {
if (!key.startsWith('0x')) {
key = '0x' + key;
}
if (!web3.utils.isHexStrict(key)) {
logger.warn(`Private key is not a HEX string in file ${accountConfig.privateKeyFile} at index ${index}`);
return null;
}
return web3.eth.accounts.privateKeyToAccount(key);
});
}
if (accountConfig.mnemonic) {
const hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(accountConfig.mnemonic.trim()));
const addressIndex = accountConfig.addressIndex || 0;
const numAddresses = accountConfig.numAddresses || 1;
const wallet_hdpath = accountConfig.hdpath || "m/44'/60'/0'/0/";
const accounts = [];
for (let i = addressIndex; i < addressIndex + numAddresses; i++) {
const wallet = hdwallet.derivePath(wallet_hdpath + i).getWallet();
accounts.push(web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')));
}
return accounts;
}
logger.warn('Unsupported account configuration: ' + JSON.stringify(accountConfig));
logger.warn('Try using one of those: ' +
'{ "privateKey": "your-private-key", "privateKeyFile": "path/to/file/containing/key", "mnemonic": "12 word mnemonic" }');
return null;
}
}
module.exports = AccountParser;

View File

@ -0,0 +1,72 @@
const async = require('async');
const TARGET = 15000000000000000000;
const ALREADY_FUNDED = 'alreadyFunded';
function fundAccount(web3, accountAddress, callback) {
let accountBalance;
let coinbaseAddress;
let lastNonce;
let gasPrice;
async.waterfall([
function getAccountBalance(next) {
web3.eth.getBalance(accountAddress, (err, balance) => {
if (err) {
return next(err);
}
if (balance >= TARGET) {
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: TARGET - accountBalance,
gasPrice: gasPrice,
nonce: lastNonce
}, next);
}
], (err) => {
if (err && err !== ALREADY_FUNDED) {
return callback(err);
}
callback();
});
}
module.exports = fundAccount;

View File

@ -1,98 +1,67 @@
const ProviderEngine = require('web3-provider-engine'); const ProviderEngine = require('web3-provider-engine');
const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js'); const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js');
const bip39 = require("bip39"); const async = require('async');
const hdkey = require('ethereumjs-wallet/hdkey'); const AccountParser = require('./accountParser');
const fs = require('../core/fs'); const fundAccount = require('./fundAccount');
const NO_ACCOUNTS = 'noAccounts';
class Provider { class Provider {
constructor(options) { constructor(options) {
const self = this;
this.web3 = options.web3; this.web3 = options.web3;
this.accountsConfig = options.accountsConfig; this.accountsConfig = options.accountsConfig;
this.web3Endpoint = options.web3Endpoint;
this.logger = options.logger; this.logger = options.logger;
this.isDev = options.isDev; this.isDev = options.isDev;
this.engine = new ProviderEngine(); this.engine = new ProviderEngine();
this.asyncMethods = {}; this.asyncMethods = {};
}
this.engine.addProvider(new RpcSubprovider({ startWeb3Provider(callback) {
rpcUrl: options.web3Endpoint const self = this;
self.engine.addProvider(new RpcSubprovider({
rpcUrl: self.web3Endpoint
})); }));
if (this.accountsConfig && this.accountsConfig.length) {
this.accounts = [];
this.addresses = [];
this.accountsConfig.forEach(accountConfig => {
const account = this.getAccount(accountConfig);
if (!account) {
return;
}
if (Array.isArray(account)) {
this.accounts = this.accounts.concat(account);
account.forEach(acc => {
this.addresses.push(acc.address);
});
return;
}
this.accounts.push(account);
this.addresses.push(account.address);
});
if (this.accounts.length) {
this.accounts.forEach(account => {
this.web3.eth.accounts.wallet.add(account);
});
this.asyncMethods = {
eth_accounts: self.eth_accounts.bind(this)
};
if (this.isDev) {
this.logger.warn('You are using your own account in the develop environment. It might not be funded.');
}
}
}
// network connectivity error // network connectivity error
this.engine.on('error', (err) => { self.engine.on('error', (err) => {
// report connectivity errors // report connectivity errors
this.logger.error(err.stack); self.logger.error(err.stack);
}); });
this.engine.start();
}
getAccount(accountConfig) { self.engine.start();
if (accountConfig.privateKey) { self.web3.setProvider(self);
if (!accountConfig.privateKey.startsWith('0x')) {
accountConfig.privateKey = '0x' + accountConfig.privateKey; self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger);
self.addresses = [];
async.waterfall([
function fundAccounts(next) {
if (!self.accounts.length) {
return next(NO_ACCOUNTS);
} }
return this.web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey); if (!self.isDev) {
return next();
} }
if (accountConfig.privateKeyFile) { async.each(self.accounts, (account, eachCb) => {
let fileContent = fs.readFileSync(fs.dappPath(accountConfig.privateKeyFile)).toString(); fundAccount(self.web3, account.address, eachCb);
fileContent = fileContent.trim().split(/[,;]/); }, next);
return fileContent.map(key => { },
if (!key.startsWith('0x')) { function populateWeb3Wallet(next) {
key = '0x' + key; self.accounts.forEach(account => {
} self.addresses.push(account.address);
return this.web3.eth.accounts.privateKeyToAccount(key); self.web3.eth.accounts.wallet.add(account);
}); });
self.asyncMethods = {
eth_accounts: self.eth_accounts.bind(self)
};
next();
} }
if (accountConfig.mnemonic) { ], function (err) {
const hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(accountConfig.mnemonic.trim())); if (err && err !== NO_ACCOUNTS) {
self.logger.error((err));
const addressIndex = accountConfig.addressIndex || 0;
const numAddresses = accountConfig.numAddresses || 1;
const wallet_hdpath = accountConfig.hdpath || "m/44'/60'/0'/0/";
const accounts = [];
for (let i = addressIndex; i < addressIndex + numAddresses; i++) {
const wallet = hdwallet.derivePath(wallet_hdpath + i).getWallet();
accounts.push(this.web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')));
} }
return accounts; callback();
} });
this.logger.warn('Unsupported account configuration: ' + JSON.stringify(accountConfig));
this.logger.warn('Try using one of those: ' +
'{ "privateKey": "your-private-key", "privateKeyFile": "path/to/file/containing/key", "mnemonic": "12 word mnemonic" }');
return null;
} }
eth_accounts(payload, cb) { eth_accounts(payload, cb) {

View File

@ -40,7 +40,7 @@ class Engine {
}, 0); }, 0);
if (this.interceptLogs || this.interceptLogs === undefined) { if (this.interceptLogs || this.interceptLogs === undefined) {
this.doInterceptLogs(); // this.doInterceptLogs();
} }
} }
@ -275,6 +275,7 @@ class Engine {
web3Service(options) { web3Service(options) {
let self = this; let self = this;
this.web3 = options.web3; this.web3 = options.web3;
let provider;
if (this.web3 === undefined) { if (this.web3 === undefined) {
this.web3 = new Web3(); this.web3 = new Web3();
if (this.config.contractsConfig.deployment.type === "rpc") { if (this.config.contractsConfig.deployment.type === "rpc") {
@ -286,12 +287,23 @@ class Engine {
isDev: this.isDev, isDev: this.isDev,
web3Endpoint web3Endpoint
}; };
this.web3.setProvider(new Provider(providerOptions)); provider = new Provider(providerOptions);
} else { } else {
throw new Error("contracts config error: unknown deployment type " + this.config.contractsConfig.deployment.type); throw new Error("contracts config error: unknown deployment type " + this.config.contractsConfig.deployment.type);
} }
} }
async.waterfall([
function (next) {
if (!provider) {
return next();
}
provider.startWeb3Provider(next);
}
], function (err) {
if (err) {
console.error(err);
}
self.servicesMonitor.addCheck('Ethereum', function (cb) { self.servicesMonitor.addCheck('Ethereum', function (cb) {
if (self.web3.currentProvider === undefined) { if (self.web3.currentProvider === undefined) {
return cb({name: __("No Blockchain node found"), status: 'off'}); return cb({name: __("No Blockchain node found"), status: 'off'});
@ -319,10 +331,11 @@ class Engine {
}); });
}); });
this.registerModule('whisper', { self.registerModule('whisper', {
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor), addCheck: self.servicesMonitor.addCheck.bind(self.servicesMonitor),
communicationConfig: this.config.communicationConfig, communicationConfig: self.config.communicationConfig,
web3: this.web3 web3: self.web3
});
}); });
} }

View File

@ -38,7 +38,7 @@ class Console {
var pluginCmds = this.plugins.getPluginsProperty('console', 'console'); var pluginCmds = this.plugins.getPluginsProperty('console', 'console');
for (let pluginCmd of pluginCmds) { for (let pluginCmd of pluginCmds) {
let pluginOutput = pluginCmd.call(this, cmd, {}); let pluginOutput = pluginCmd.call(this, cmd, {});
if (pluginOutput !== false && pluginOutput !== 'false') return callback(pluginOutput); if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) return callback(pluginOutput);
} }
let output = this.processEmbarkCmd(cmd); let output = this.processEmbarkCmd(cmd);

View File

@ -270,6 +270,12 @@ class Dashboard {
border: { border: {
type: "line" type: "line"
}, },
scrollable: true,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
style: { style: {
fg: -1, fg: -1,
border: { border: {

View File

@ -3,7 +3,6 @@
"Contract Name": "Contract Name", "Contract Name": "Contract Name",
"New Application": "New Application", "New Application": "New Application",
"create a barebones project meant only for contract development": "create a barebones project meant only for contract development", "create a barebones project meant only for contract development": "create a barebones project meant only for contract development",
"language to use (default: en)": "language to use (default: en)",
"create a working dapp with a SimpleStorage contract": "create a working dapp with a SimpleStorage contract", "create a working dapp with a SimpleStorage contract": "create a working dapp with a SimpleStorage contract",
"filename to output logs (default: none)": "filename to output logs (default: none)", "filename to output logs (default: none)": "filename to output logs (default: none)",
"level of logging to display": "level of logging to display", "level of logging to display": "level of logging to display",
@ -26,9 +25,6 @@
"custom gas limit (default: %s)": "custom gas limit (default: %s)", "custom gas limit (default: %s)": "custom gas limit (default: %s)",
"run tests": "run tests", "run tests": "run tests",
"resets embarks state on this dapp including clearing cache": "resets embarks state on this dapp including clearing cache", "resets embarks state on this dapp including clearing cache": "resets embarks state on this dapp including clearing cache",
"Graph will not include undeployed contracts": "Graph will not include undeployed contracts",
"Graph will not include functions": "Graph will not include functions",
"Graph will not include events": "Graph will not include events",
"generates documentation based on the smart contracts configured": "generates documentation based on the smart contracts configured", "generates documentation based on the smart contracts configured": "generates documentation based on the smart contracts configured",
"Upload your dapp to a decentralized storage": "Upload your dapp to a decentralized storage", "Upload your dapp to a decentralized storage": "Upload your dapp to a decentralized storage",
"output the version number": "output the version number", "output the version number": "output the version number",
@ -42,12 +38,7 @@
"dashboard start": "dashboard start", "dashboard start": "dashboard start",
"loaded plugins": "loaded plugins", "loaded plugins": "loaded plugins",
"loading solc compiler": "loading solc compiler", "loading solc compiler": "loading solc compiler",
"Cannot upload: {{platform}} node is not running on {{url}}.": "Cannot upload: {{platform}} node is not running on {{url}}.",
"http:// Cannot upload: {{platform}} node is not running on {{url}}.": "http:// Cannot upload: {{platform}} node is not running on {{url}}.",
"Cannot upload:": "Cannot upload:",
"node is not running on": "node is not running on",
"compiling solidity contracts": "compiling solidity contracts", "compiling solidity contracts": "compiling solidity contracts",
"Cannot upload: {{platform}} node is not running on {{protocol}}://{{host}}:{{port}}.": "Cannot upload: {{platform}} node is not running on {{protocol}}://{{host}}:{{port}}.",
"%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.": "%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.", "%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.": "%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.",
"assuming %s to be an interface": "assuming %s to be an interface", "assuming %s to be an interface": "assuming %s to be an interface",
"{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: couldn't find instanceOf contract {{parentContractName}}", "{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: couldn't find instanceOf contract {{parentContractName}}",
@ -79,15 +70,15 @@
"to immediatly exit (alias: exit)": "to immediatly exit (alias: exit)", "to immediatly exit (alias: exit)": "to immediatly exit (alias: exit)",
"The web3 object and the interfaces for the deployed contracts and their methods are also available": "The web3 object and the interfaces for the deployed contracts and their methods are also available", "The web3 object and the interfaces for the deployed contracts and their methods are also available": "The web3 object and the interfaces for the deployed contracts and their methods are also available",
"versions in use": "versions in use", "versions in use": "versions in use",
"language to use (default: en)": "language to use (default: en)",
"executing": "executing", "executing": "executing",
"finished deploying": "finished deploying",
"writing file": "writing file", "writing file": "writing file",
"errors found while generating": "errors found while generating", "errors found while generating": "errors found while generating",
"deploying to swarm!": "deploying to swarm!",
"adding %s to swarm": "adding %s to swarm",
"error uploading to swarm": "error uploading to swarm",
"Looking for documentation? You can find it at": "Looking for documentation? You can find it at", "Looking for documentation? You can find it at": "Looking for documentation? You can find it at",
"Ready": "Ready", "Ready": "Ready",
"Graph will not include undeployed contracts": "Graph will not include undeployed contracts",
"Graph will not include functions": "Graph will not include functions",
"Graph will not include events": "Graph will not include events",
"Embark Blockchain Using: %s": "Embark Blockchain Using: %s", "Embark Blockchain Using: %s": "Embark Blockchain Using: %s",
"running: %s": "running: %s", "running: %s": "running: %s",
"Initializing Embark Template....": "Initializing Embark Template....", "Initializing Embark Template....": "Initializing Embark Template....",
@ -118,5 +109,9 @@
"adding %s to ipfs": "adding %s to ipfs", "adding %s to ipfs": "adding %s to ipfs",
"DApp available at": "DApp available at", "DApp available at": "DApp available at",
"successfully uploaded to ipfs": "successfully uploaded to ipfs", "successfully uploaded to ipfs": "successfully uploaded to ipfs",
"Ethereum node (version unknown)": "Ethereum node (version unknown)",
"No Blockchain node found": "No Blockchain node found",
"Couldn't connect to an Ethereum node are you sure it's on?": "Couldn't connect to an Ethereum node are you sure it's on?",
"make sure you have an Ethereum node or simulator running. e.g '%s'": "make sure you have an Ethereum node or simulator running. e.g '%s'",
"finished building DApp and deploying to": "finished building DApp and deploying to" "finished building DApp and deploying to": "finished building DApp and deploying to"
} }

View File

@ -1,188 +1,188 @@
{ {
"New Application": "Nova Aplicacao", "New Application": "Nueva Aplicación",
"Contract Name": "Contracto", "Contract Name": "Nombre del Contrato",
"Address": "Endereço", "Address": "Dirección",
"Status": "Estado", "Status": "Estado",
"Embark Blockchain Using: %s": "Embark Blockchain esta usando o commando: %s", "Embark Blockchain Using: %s": "Embark Blockchain esta usando el comando: %s",
"running: %s": "executando: %s", "running: %s": "ejecutando: %s",
"already initialized": "ja esta inicializado", "already initialized": "ya esta inicializado",
"create a barebones project meant only for contract development": "criar um projeto vazio destinado apenas ao desenvolvimento de contratos", "create a barebones project meant only for contract development": "crear un proyecto vacio destinado solo para el desarrollo de contratos",
"loading solc compiler": "carregando o compilador solc", "loading solc compiler": "cargando el compilador solc",
"Welcome to Embark": "Bem-vindo ao Embark", "Welcome to Embark": "Bienvenido a Embark",
"possible commands are:": "comandos possíveis são:", "possible commands are:": "los comandos posibles son:",
"display versions in use for libraries and tools like web3 and solc": "lista versões em uso para bibliotecas e ferramentas como web3 e solc", "display versions in use for libraries and tools like web3 and solc": "mostrar versiones en uso para bibliotecas y herramientas como web3 y solc",
"instantiated web3.js object configured to the current environment": "objeto web3.js instanciado configurado para o ambiente atual", "instantiated web3.js object configured to the current environment": "objeto web3.js instanciado configurado para el entorno actual",
"to immediatly exit (alias: exit)": "para sair imediatamente (alias: exit)", "to immediatly exit (alias: exit)": "para salir inmediatamente (alias: exit)",
"The web3 object and the interfaces for the deployed contracts and their methods are also available": "O objeto web3 e as interfaces para os contratos implantados e seus métodos também estão disponíveis", "The web3 object and the interfaces for the deployed contracts and their methods are also available": "El objeto web3 y las interfaces para los contratos publicados y sus métodos también están disponibles",
"create a working dapp with a SimpleStorage contract": "Cria uma dapp funcional com o contrato SimpleStorage", "create a working dapp with a SimpleStorage contract": "Crear una dapp funcional con un contrato SimpleStorage",
"filename to output logs (default: none)": "ficheiro/arquivo para saída dos logs (predefinido: none)", "filename to output logs (default: none)": "fichero/archivo para salida de los logs (predefinido: none)",
"level of logging to display": "nivel do log", "level of logging to display": "nivel de log para mostrar",
"deploy and build dapp at ": "Publica os contractos e constroi a applicacao em ", "deploy and build dapp at ": "Publica los contractos y construye la aplicación en ",
"port to run the dev webserver (default: %s)": "porta para correr o servidor web para desenvolvimento (default: %s)", "port to run the dev webserver (default: %s)": "puerto para correr el servidor web para desarrollo (default: %s)",
"host to run the dev webserver (default: %s)": "host para correr o servidor web para desenvolvimento (default: %s)", "host to run the dev webserver (default: %s)": "host para correr el servidor web para desarrollo (default: %s)",
"disable the development webserver": "disativa o servidor web para desenvolvimento", "disable the development webserver": "desactiva el servidor web para desarrollo",
"simple mode, disables the dashboard": "modo simples, disativa o dashboard", "simple mode, disables the dashboard": "modo simple, desactiva el dashboard",
"no colors in case it's needed for compatbility purposes": "sem cores, em caso seja necessario para compabitilidade com a terminal", "no colors in case it's needed for compatbility purposes": "Sin colores, en caso de ser necessario para compatibilidad con la terminal",
"filename to output logs (default: %s)": "ficheiro/arquivo para os logs (predefinido: %s)", "filename to output logs (default: %s)": "fichero/archivo para los logs (predefinido: %s)",
"run dapp (default: %s)": "executa a dapp (applicacao decentralizada) (predefinido: %s)", "run dapp (default: %s)": "ejecutar la dapp (applicación decentralizada) (predefinido: %s)",
"Use a specific ethereum client or simulator (supported: %s)": "Usa um cliente ou simulador de ethereum específico (supportado: %s)", "Use a specific ethereum client or simulator (supported: %s)": "Usa un cliente o un simulador de ethereum específico (soportado: %s)",
"run blockchain server (default: %s)": "executa un node de blockchain (predefinido: %s)", "run blockchain server (default: %s)": "ejecuta un nodo de blockchain (predefinido: %s)",
"run a fast ethereum rpc simulator": "executa um simulador RPC de ethereum", "run a fast ethereum rpc simulator": "ejecuta un simulador RPC de ethereum",
"use testrpc as the rpc simulator [%s]": "usa testrpc como simulator de rpc [%s]", "use testrpc as the rpc simulator [%s]": "usa testrpc como simulator de rpc [%s]",
"port to run the rpc simulator (default: %s)": "porta para executar simulador de rpc (predefinido: %s)", "port to run the rpc simulator (default: %s)": "puerto para ejecutar un simulador de rpc (predefinido: %s)",
"host to run the rpc simulator (default: %s)": "host para executar servidor de rpc (predefinido: %s)", "host to run the rpc simulator (default: %s)": "host para ejecutar un servidor de rpc (predefinido: %s)",
"number of accounts (default: %s)": "numero de contas (predefinido: %s)", "number of accounts (default: %s)": "número de cuentas (predefinido: %s)",
"Amount of ether to assign each test account (default: %s)": "Quantidade de éter para atribuir cada conta de teste (predefinido: %s)", "Amount of ether to assign each test account (default: %s)": "Cantidad de éter para asignar a cada cuenta de prueba (predefinido: %s)",
"custom gas limit (default: %s)": "limite de gás (predefinido: %s)", "custom gas limit (default: %s)": "límite de gas (predefinido: %s)",
"run tests": "executar os testes", "run tests": "ejecutar las pruebas",
"resets embarks state on this dapp including clearing cache": "recomenca o estado do Embark nesta appliacao, incluindo a cache", "resets embarks state on this dapp including clearing cache": "restablece el estado de Embark en esta dapp, incluida la eliminación de la memoria caché",
"generates documentation based on the smart contracts configured": "gera documentação baseada nos contratos configurados", "generates documentation based on the smart contracts configured": "genera documentación basada en los contratos inteligentes configurados",
"Upload your dapp to a decentralized storage": "Carrega a appliacao para armazenamento descentralizado", "Upload your dapp to a decentralized storage": "Suba su dapp a un almacenamiento descentralizado",
"output the version number": "produz a versão actual", "output the version number": "mostrar el número de versión",
"Logs": "Logs", "Logs": "Logs",
"Environment": "Ambiente", "Environment": "Ambiente",
"Available Services": "Serviços Disponíveis", "Available Services": "Servicios Disponibles",
"Contracts": "Contratos", "Contracts": "Contratos",
"Console": "Consola", "Console": "Consola",
"dashboard start": "inicia o painel de controle", "dashboard start": "inicia el panel de control",
"loaded plugins": "plugins carregados", "loaded plugins": "plugins cargados",
"compiling solidity contracts": "Compilando contratos Solidity", "compiling solidity contracts": "Compilando contratos Solidity",
"%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.": "%s não tem um compilador de contrato compatível. Talvez exista um plugin para isso.", "%s doesn't have a compatible contract compiler. Maybe a plugin exists for it.": "%s no tiene un compilador de contrato compatible. Tal vez existe un plugin para ello.",
"assuming %s to be an interface": "assumindo que %s é uma interface", "assuming %s to be an interface": "suponiendo que %s sea una interfaz",
"{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: não foi possível encontrar instancia de (instanceOf) do contrato {{parentContractName}}", "{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: no se pudo encontrar la instancia (instanceOf) del contrato {{parentContractName}}",
"did you mean \"%s\"?": "você quis dizer \"%s\"?", "did you mean \"%s\"?": "querías decir \"%s\"?",
"%s has no code associated": "%s não tem código associado", "%s has no code associated": "%s no tiene código asociado",
"deploying contracts": "publicando contratos", "deploying contracts": "publicando contratos",
"running beforeDeploy plugin %s .": "executando plugin beforeDeploy %s .", "running beforeDeploy plugin %s .": "ejecutanto plugin beforeDeploy %s .",
"deploying": "publicando", "deploying": "publicando",
"with": "com", "with": "con",
"gas": "gas", "gas": "gas",
"Pending": "Pendente", "Pending": "Pendiente",
"Interface or set to not deploy": "Interface ou configurado para não ser publicado", "Interface or set to not deploy": "Interfaz o configurado para no publicar",
"error deploying": "erro de publicação", "error deploying": "error publicando",
"due to error": "devido a erro", "due to error": "debido a error",
"error deploying contracts": "erro publicando contratos", "error deploying contracts": "error publicando contratos",
"finished deploying contracts": "publicação de contratos concluida", "finished deploying contracts": "publicación de contratos concluida",
"error running afterDeploy: ": "erro executado afterDeploy: ", "error running afterDeploy: ": "error ejecutando afterDeploy: ",
"ready to watch file changes": "pronto para monitorar alterações em ficheiros/arquivos", "ready to watch file changes": "listo para monitorear alteraciones en ficheros/archivos",
"Starting Server": "iniciando o servidor", "Starting Server": "iniciando el servidor",
"webserver available at": "servidor web disponivel em", "webserver available at": "servidor web disponible en",
"Webserver": "Servidor Web", "Webserver": "Servidor Web",
" already deployed at ": " já publicado em ", " already deployed at ": " ya publicado en ",
"Deployed": "Publicado", "Deployed": "Publicado",
"Name must be only letters, spaces, or dashes": "O nome deve ser apenas letras, espaços ou traços", "Name must be only letters, spaces, or dashes": "El nombre debe ser solo letras, espacios o guiones",
"Name your app (default is %s)": "Nome da aplicacao (predefinido is %s)", "Name your app (default is %s)": "Nombre su aplicación (el valor predeterminado es %s)",
"Invalid name": "Nome inválido", "Invalid name": "Nombre inválido",
"unknown command": "comando desconhecido", "unknown command": "comando desconocido",
"did you mean": "você quis dizer", "did you mean": "querías decir",
"warning: running default config on a non-development environment": "aviso: executando a configuração padrão em um ambiente de não desenvolvimento", "warning: running default config on a non-development environment": "aviso: ejecutando la configuración predefinida en un ambiente de no-desarrollo",
"could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?": "não foi possível encontrar o comando {{geth_bin}}; o {{client_name}} instalado ou no PATH?", "could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?": "no se pudo encontrar el comando {{geth_bin}}; ¿Está {{client_name}} instalado o en la RUTA?",
"no accounts found": "nenhuma conta encontrada", "no accounts found": "no se encontraron cuentas",
"initializing genesis block": "inicializando o bloco de gênese", "initializing genesis block": "inicializando bloque genesis",
"rpcCorsDomain set to *": "rpcCorsDomain definido como *", "rpcCorsDomain set to *": "rpcCorsDomain definido como *",
"make sure you know what you are doing": "certifique-se de saber o que está fazendo", "make sure you know what you are doing": "asegúrate de saber lo que estás haciendo",
"warning: cors is not set": "aviso: cors não está definido", "warning: cors is not set": "aviso: cors no está definido",
"wsOrigins set to *": "wsOrigins definido como *", "wsOrigins set to *": "wsOrigins definido como *",
"warning: wsOrigins is not set": "aviso: wsOrigins não está definido", "warning: wsOrigins is not set": "aviso: wsOrigins no está definido",
"reset done!": "reset feito!", "reset done!": "reset listo!",
"%s is not installed on your machine": "%s não está instalado na sua máquina", "%s is not installed on your machine": "%s no está instalado en su máquina",
"You can install it by running: %s": "Você pode instalá-lo executando: %s", "You can install it by running: %s": "Puede instalarlo ejecutando: %s",
"Initializing Embark Template....": "Inicializando Embark Template....", "Initializing Embark Template....": "Inicializando la plantilla de Embark....",
"Installing packages...": "Instalando pacotes...", "Installing packages...": "Instalando paquetes...",
"Init complete": "Init complete", "Init complete": "Init completo",
"App ready at ": "App ready at ", "App ready at ": "Aplicación lista en ",
"Next steps:": "Next steps:", "Next steps:": "Próximos pasos:",
"open another console in the same directory and run": "open another console in the same directory and run", "open another console in the same directory and run": "abrir otra consola en el mismo directorio y ejecutar",
"For more info go to http://embark.status.im": "For more info go to http://embark.status.im", "For more info go to http://embark.status.im": "Para más información ve a http://embark.status.im",
"%s : instanceOf is set to itself": "%s : instanceOf is set to itself", "%s : instanceOf is set to itself": "%s : instanceOf se establece a sí mismo",
"{{className}} has code associated to it but it's configured as an instanceOf {{parentContractName}}": "{{className}} has code associated to it but it's configured as an instanceOf {{parentContractName}}", "{{className}} has code associated to it but it's configured as an instanceOf {{parentContractName}}": "{{className}} tiene un código asociado pero está configurado como una instancia de {{parentContractName}}",
"Error Compiling/Building contracts: ": "Error Compiling/Building contracts: ", "Error Compiling/Building contracts: ": "Error Compilando/Construyendo los contractos: ",
"Error: ": "Error: ", "Error: ": "Error: ",
"there are two or more contracts that depend on each other in a cyclic manner": "there are two or more contracts that depend on each other in a cyclic manner", "there are two or more contracts that depend on each other in a cyclic manner": "hay dos o más contratos que dependen el uno del otro de forma cíclica",
"Embark couldn't determine which one to deploy first": "Embark couldn't determine which one to deploy first", "Embark couldn't determine which one to deploy first": "Embark no pudo determinar cual publicar primero",
"{{inputName}} has not been defined for {{className}} constructor": "{{inputName}} has not been defined for {{className}} constructor", "{{inputName}} has not been defined for {{className}} constructor": "{{inputName}} no ha sido definido para el constructor de {{className}}",
"error deploying %s": "error deploying %s", "error deploying %s": "error publicando %s",
"executing onDeploy commands": "executing onDeploy commands", "executing onDeploy commands": "ejecutando comandos onDeploy",
"error executing onDeploy for ": "error executing onDeploy for ", "error executing onDeploy for ": "error ejecutando onDeploy para ",
" does not exist": " does not exist", " does not exist": " no existe",
"error running onDeploy: ": "error running onDeploy: ", "error running onDeploy: ": "error ejecutando onDeploy: ",
" exists but has been set to not deploy": " exists but has been set to not deploy", " exists but has been set to not deploy": " existe, pero se ha configurado para no implementar",
"couldn't find a valid address for %s has it been deployed?": "couldn't find a valid address for %s has it been deployed?", "couldn't find a valid address for %s has it been deployed?": "no pudo encontrar una dirección válida para %s ¿ha sido publicado?",
"executing: ": "executing: ", "executing: ": "ejecutando: ",
"the transaction was rejected; this usually happens due to a throw or a require": "the transaction was rejected; this usually happens due to a throw or a require", "the transaction was rejected; this usually happens due to a throw or a require": "la transacción fue rechazada; esto generalmente sucede debido a un throw o a un require",
"no account found at index": "no account found at index", "no account found at index": "no se encontró una cuenta en index",
" check the config": " check the config", " check the config": " verifique la configuración",
"Both \"from\" and \"fromIndex\" are defined for contract": "Both \"from\" and \"fromIndex\" are defined for contract", "Both \"from\" and \"fromIndex\" are defined for contract": "Ambos \"from\" y \"fromIndex\" están definidos para el contracto",
"Using \"from\" as deployer account.": "Using \"from\" as deployer account.", "Using \"from\" as deployer account.": "Usando \"from\" como cuenta de implementación.",
"{{linkReference}} is too long": "{{linkReference}} is too long", "{{linkReference}} is too long": "{{linkReference}} es muy largo",
"{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?": "{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", "{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?": "{{contractName}} necesita {{libraryName}} pero no se encontró una dirección, ¿la implementó o configuró una dirección?",
"attempted to deploy %s without specifying parameters": "attempted to deploy %s without specifying parameters", "attempted to deploy %s without specifying parameters": "intentado publicar %s sin especificar parámetros",
"deployed at": "deployed at", "deployed at": "publicado en",
"no contracts found": "no contracts found", "no contracts found": "no hay contractos encontrados",
"Blockchain component is disabled in the config": "Blockchain component is disabled in the config", "Blockchain component is disabled in the config": "El componente Blockchain está deshabilitado en la configuración",
"Couldn't connect to an Ethereum node are you sure it's on?": "Couldn't connect to an Ethereum node are you sure it's on?", "Couldn't connect to an Ethereum node are you sure it's on?": "No se pudo conectar a un nodo Ethereum, ¿está seguro de que está activado?",
"make sure you have an Ethereum node or simulator running. e.g '%s'": "make sure you have an Ethereum node or simulator running. e.g '%s'", "make sure you have an Ethereum node or simulator running. e.g '%s'": "asegurese de tener un nodo o simulador Ethereum en funcionamiento. e.g '%s'",
"executing": "executing", "executing": "ejecutando",
"the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation": "the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation", "the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation": "la transacción fue rechazada; esto generalmente ocurre debido a un throw o un require, también puede ocurrir debido a una operación no válida",
"Cannot find file %s Please ensure you are running this command inside the Dapp folder": "Cannot find file %s Please ensure you are running this command inside the Dapp folder", "Cannot find file %s Please ensure you are running this command inside the Dapp folder": "No se puede encontrar el archivo %s Asegúrese de que está ejecutando este comando dentro de la carpeta de la DApp",
"no config file found at %s using default config": "no config file found at %s using default config", "no config file found at %s using default config": "archivo de configuración no encontrado en %s utilizado la configuración predefinida",
"HTTP contract file not found": "HTTP contract file not found", "HTTP contract file not found": "archivo de contracto HTTP no encontrado",
"contract file not found": "contract file not found", "contract file not found": "archivo de contracto no encontrado",
"file not found, creating it...": "file not found, creating it...", "file not found, creating it...": "archivo no encontrado, creándolo ...",
"No Blockchain node found": "No Blockchain node found", "No Blockchain node found": "No se encontró ningún nodo de Blockchain",
"Ethereum node (version unknown)": "Ethereum node (version unknown)", "Ethereum node (version unknown)": "Nodo Ethereum (versión desconocida)",
"this event is deprecated and will be removed in future versions %s": "this event is deprecated and will be removed in future versions %s", "this event is deprecated and will be removed in future versions %s": "este evento está en desuso y se eliminará en futuras versiones %s",
"Error while downloading the file": "Error while downloading the file", "Error while downloading the file": "Error descargando el archivo",
"Plugin {{name}} can only be loaded in the context of \"{{contextes}}\"": "Plugin {{name}} can only be loaded in the context of \"{{contextes}}\"", "Plugin {{name}} can only be loaded in the context of \"{{contextes}}\"": "El complemento {{name}} solo se puede cargar en el contexto de \"{{contextes}} \"",
"error running service check": "error running service check", "error running service check": "error al ejecutar la comprobación del servicio",
"help": "ajuda", "help": "ayuda",
"quit": "sair", "quit": "salir",
"Type": "Type", "Type": "Tipo",
"to see the list of available commands": "to see the list of available commands", "to see the list of available commands": "para ver la lista de comandos disponibles",
"Asset Pipeline": "Asset Pipeline", "Asset Pipeline": "Asset Pipeline",
"Ethereum node detected": "Ethereum node detected", "Ethereum node detected": "Nodo Ethereum detectado",
"Deployment Done": "Deployment Done", "Deployment Done": "Publicación completada",
"Looking for documentation? You can find it at": "A procura de Documentacao? pode encontra-la em", "Looking for documentation? You can find it at": "¿Buscando documentación? puede encontrarla en",
"Ready": "Ready", "Ready": "Listo",
"tip: you can resize the terminal or disable the dashboard with": "tip: you can resize the terminal or disable the dashboard with", "tip: you can resize the terminal or disable the dashboard with": "consejo: puede redimensionar la terminal o desactivar el tablero con",
"finished building": "finished building", "finished building": "construcción completada",
"Done": "Done", "Done": "Hecho",
"Cannot upload: {{platform}} node is not running on {{url}}.": "Cannot upload: {{platform}} node is not running on {{url}}.", "Cannot upload: {{platform}} node is not running on {{url}}.": "No se puede cargar: el nodo {{platform}} no se está ejecutando en {{url}}.",
"try \"{{ipfs}}\" or \"{{swarm}}\"": "try \"{{ipfs}}\" or \"{{swarm}}\"", "try \"{{ipfs}}\" or \"{{swarm}}\"": "intente \"{{ipfs}}\" o \"{{swarm}}\"",
"finished deploying": "finished deploying", "finished deploying": "publicación completada",
"finished building DApp and deploying to": "finished building DApp and deploying to", "finished building DApp and deploying to": "construcción de la DApp completada y publicada en",
"IPFS node detected": "IPFS node detected", "IPFS node detected": "Nodo de IPFS detectado",
"IPFS node is offline": "IPFS node is offline", "IPFS node is offline": "Nodo de IPFS no está en línea",
"not found or not in the path. Guessing %s for path": "not found or not in the path. Guessing %s for path", "not found or not in the path. Guessing %s for path": "no encontrado o no se encuentra en la ruta. Estimando %s para la ruta",
"adding %s to ipfs": "adding %s to ipfs", "adding %s to ipfs": "añadiendo %s a ipfs",
"DApp available at": "DApp available at", "DApp available at": "DApp disponible en",
"error uploading to ipfs": "error uploading to ipfs", "error uploading to ipfs": "error cargando a ipfs",
"successfully uploaded to ipfs": "successfully uploaded to ipfs", "successfully uploaded to ipfs": "cargado con éxito a ipfs",
"Error while loading the content of ": "Error while loading the content of ", "Error while loading the content of ": "Error al cargar el contenido de ",
"error compiling for unknown reasons": "error compiling for unknown reasons", "error compiling for unknown reasons": "error compilando por razones desconocidas",
"error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code": "error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code", "error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code": "error compilando. Hay fuentes disponibles pero no se pudo compilar ningún código, probablemente debido a errores fatales en el código solidity",
"Swarm node detected...": "Swarm node detected...", "Swarm node detected...": "nodo Swarm detectado...",
"Swarm node is offline...": "Swarm node is offline...", "Swarm node is offline...": "el nodo de Swarm no se encuentra en línea...",
"deploying to swarm!": "deploying to swarm!", "deploying to swarm!": "publicando en swarm!",
"adding %s to swarm": "adding %s to swarm", "adding %s to swarm": "añadiendo %s a swarm",
"error uploading to swarm": "error uploading to swarm", "error uploading to swarm": "error cargando a swarm",
"successfully uploaded to swarm": "successfully uploaded to swarm", "successfully uploaded to swarm": "cargado exitosamente a swarm",
"Vyper exited with error code ": "Vyper exited with error code ", "Vyper exited with error code ": "Vyper salió con el código de error ",
"Execution returned no result": "Execution returned no result", "Execution returned no result": "La ejecución no devolvió resultados",
"compiling Vyper contracts": "compiling Vyper contracts", "compiling Vyper contracts": "compilando contractos Vyper",
"Webserver is offline": "Webserver is offline", "Webserver is offline": "el servidor web no se encuentra en línea",
"stopping webserver": "stopping webserver", "stopping webserver": "deteniendo el servidor web",
"a webserver is already running at": "a webserver is already running at", "a webserver is already running at": "un servidor web ya se está ejecutando en",
"no webserver is currently running": "no webserver is currently running", "no webserver is currently running": "ningún servidor web se está ejecutando actualmente",
"couldn't find file": "couldn't find file", "couldn't find file": "el archivo no pudo ser encontrado",
"errors found while generating": "errors found while generating", "errors found while generating": "errores encontrados al generar",
"writing file": "escrevendo ficheiro", "writing file": "escribiendo archivo",
"Simulator not found; Please install it with \"%s\"": "Simulator not found; Please install it with \"%s\"", "Simulator not found; Please install it with \"%s\"": "Simulador no encontrado; Por favor instalarlo con \"%s\"",
"Tried to load testrpc but an error occurred. This is a problem with testrpc": "Tried to load testrpc but an error occurred. This is a problem with testrpc", "Tried to load testrpc but an error occurred. This is a problem with testrpc": "Intenté cargar testrpc pero ocurrió un error. Este es un problema con testrpc",
"IMPORTANT: if you using a NodeJS version older than 6.9.1 then you need to install an older version of testrpc \"%s\". Alternatively install node 6.9.1 and the testrpc 3.0": "IMPORTANT: if you using a NodeJS version older than 6.9.1 then you need to install an older version of testrpc \"%s\". Alternatively install node 6.9.1 and the testrpc 3.0", "IMPORTANT: if you using a NodeJS version older than 6.9.1 then you need to install an older version of testrpc \"%s\". Alternatively install node 6.9.1 and the testrpc 3.0": "IMPORTANTE: si usa una versión de NodeJS anterior a la 6.9.1, entonces necesita instalar una versión anterior de testrpc \"%s\". Alternativamente, instale el Node 6.9.1 y el testrpc 3.0",
"terminating due to error": "terminating due to error", "terminating due to error": "terminando debido a un error",
"There a a space in the version of {{versionKey}}. We corrected it for you ({{correction})": "There a a space in the version of {{versionKey}}. We corrected it for you ({{correction})", "There a a space in the version of {{versionKey}}. We corrected it for you ({{correction})": "Hay un espacio en la versión de {{versionKey}}. Lo corregimos por ti ({{correction})",
"versions": "versions", "versions": "versiones",
"versions in use": "versions in use", "versions in use": "versiones en uso",
"downloading {{packageName}} {{version}}....": "downloading {{packageName}} {{version}}...." "downloading {{packageName}} {{version}}....": "descargando {{packageName}} {{version}}...."
} }

View File

@ -47,6 +47,7 @@ class Profiler {
self.logger.info("-- profile for " + contractName); self.logger.info("-- profile for " + contractName);
this.profile(contractName, contract); this.profile(contractName, contract);
}); });
return "";
} }
return false; return false;
}); });

View File

@ -7,6 +7,8 @@ class Solidity {
this.logger = embark.logger; this.logger = embark.logger;
this.events = embark.events; this.events = embark.events;
this.contractDirectories = options.contractDirectories; this.contractDirectories = options.contractDirectories;
this.solcAlreadyLoaded = false;
this.solcW = null;
embark.registerCompiler(".sol", this.compile_solidity.bind(this)); embark.registerCompiler(".sol", this.compile_solidity.bind(this));
} }
@ -17,7 +19,6 @@ class Solidity {
} }
let self = this; let self = this;
let input = {}; let input = {};
let solcW;
async.waterfall([ async.waterfall([
function prepareInput(callback) { function prepareInput(callback) {
async.each(contractFiles, async.each(contractFiles,
@ -44,14 +45,14 @@ class Solidity {
); );
}, },
function loadCompiler(callback) { function loadCompiler(callback) {
// TODO: there ino need to load this twice if (self.solcAlreadyLoaded) {
solcW = new SolcW({logger: self.logger, events: self.events});
if (solcW.isCompilerLoaded()) {
return callback(); return callback();
} }
self.solcW = new SolcW({logger: self.logger, events: self.events});
self.logger.info(__("loading solc compiler") + ".."); self.logger.info(__("loading solc compiler") + "..");
solcW.load_compiler(function (err) { self.solcW.load_compiler(function (err) {
self.solcAlreadyLoaded = true;
callback(err); callback(err);
}); });
}, },
@ -73,7 +74,7 @@ class Solidity {
} }
}; };
solcW.compile(jsonObj, function (output) { self.solcW.compile(jsonObj, function (output) {
if (output.errors) { if (output.errors) {
for (let i=0; i<output.errors.length; i++) { for (let i=0; i<output.errors.length; i++) {
if (output.errors[i].type === 'Warning') { if (output.errors[i].type === 'Warning') {

View File

@ -1,11 +1,13 @@
let solc;
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const constants = require('../../constants'); const constants = require('../../constants');
const Utils = require('../../utils/utils'); const Utils = require('../../utils/utils');
function findImports(filename) { const ProcessWrapper = require('../../process/processWrapper');
class SolcProcess extends ProcessWrapper {
findImports(filename) {
if (filename.startsWith('http') || filename.startsWith('git')) { if (filename.startsWith('http') || filename.startsWith('git')) {
const fileObj = Utils.getExternalContractUrl(filename); const fileObj = Utils.getExternalContractUrl(filename);
filename = fileObj.filePath; filename = fileObj.filePath;
@ -22,20 +24,35 @@ function findImports(filename) {
return {error: 'File not found'}; return {error: 'File not found'};
} }
loadCompiler(solcLocation) {
this.solc = require(solcLocation);
}
compile(jsonObj, cb) {
// TODO: only available in 0.4.11; need to make versions warn about this
let output = this.solc.compileStandardWrapper(JSON.stringify(jsonObj), this.findImports);
cb(output);
}
}
let solcProcess;
process.on('message', function (msg) { process.on('message', function (msg) {
if (msg.action === "init") {
solcProcess = new SolcProcess(msg.options);
return process.send({result: "initiated"});
}
if (msg.action === 'loadCompiler') { if (msg.action === 'loadCompiler') {
solc = require(msg.solcLocation); solcProcess.loadCompiler(msg.requirePath);
process.send({result: "loadedCompiler"}); process.send({result: "loadedCompiler"});
} }
if (msg.action === 'compile') { if (msg.action === 'compile') {
// TODO: only available in 0.4.11; need to make versions warn about this solcProcess.compile(msg.jsonObj, (output) => {
let output = solc.compileStandardWrapper(JSON.stringify(msg.jsonObj), findImports);
process.send({result: "compilation", output: output}); process.send({result: "compilation", output: output});
});
} }
}); });
process.on('exit', function () {
process.exit(0);
});

View File

@ -1,58 +1,59 @@
let utils = require('../../utils/utils.js'); let utils = require('../../utils/utils.js');
let fs = require('../../core/fs.js'); let fs = require('../../core/fs.js');
let solcProcess;
let compilerLoaded = false;
let currentSolcVersion = require('../../../package.json').dependencies.solc; let currentSolcVersion = require('../../../package.json').dependencies.solc;
const ProcessLauncher = require('../../process/processLauncher');
class SolcW { class SolcW {
constructor(options) { constructor(options) {
this.logger = options.logger; this.logger = options.logger;
this.events = options.events; this.events = options.events;
this.compilerLoaded = false;
this.solcProcess = null;
} }
load_compiler(done) { load_compiler(done) {
const self = this; const self = this;
if (compilerLoaded) { if (this.compilerLoaded) {
done(); return done();
} }
solcProcess = require('child_process').fork(utils.joinPath(__dirname, '/solcP.js')); this.solcProcess = new ProcessLauncher({
solcProcess.once('message', function (msg) { modulePath: utils.joinPath(__dirname, 'solcP.js'),
if (msg.result !== 'loadedCompiler') { logger: self.logger,
return; events: self.events
} });
compilerLoaded = true; this.solcProcess.send({action: "init", options: {}});
this.solcProcess.once('result', 'loadedCompiler', () => {
self.compilerLoaded = true;
done(); done();
}); });
this.events.request("version:get:solc", function(solcVersion) { this.events.request("version:get:solc", function(solcVersion) {
if (solcVersion === currentSolcVersion) { if (solcVersion === currentSolcVersion) {
solcProcess.send({action: 'loadCompiler', solcLocation: 'solc'}); self.solcProcess.send({action: 'loadCompiler', requirePath: 'solc'});
} else { } else {
self.events.request("version:getPackageLocation", "solc", solcVersion, function(err, location) { self.events.request("version:getPackageLocation", "solc", solcVersion, function(err, location) {
if (err) { if (err) {
return done(err); return done(err);
} }
let requirePath = fs.dappPath(location); let requirePath = fs.dappPath(location);
solcProcess.send({action: 'loadCompiler', solcLocation: requirePath}); self.solcProcess.send({action: 'loadCompiler', requirePath: requirePath});
}); });
} }
}); });
} }
isCompilerLoaded() { isCompilerLoaded() {
return (compilerLoaded === true); return (this.compilerLoaded === true);
} }
compile(jsonObj, done) { compile(jsonObj, done) {
solcProcess.once('message', function (msg) { this.solcProcess.once('result', 'compilation', (msg) => {
if (msg.result !== 'compilation') {
return;
}
done(JSON.parse(msg.output)); done(JSON.parse(msg.output));
}); });
solcProcess.send({action: 'compile', jsonObj: jsonObj});
this.solcProcess.send({action: 'compile', jsonObj: jsonObj});
} }
} }

View File

@ -100,7 +100,7 @@ class Pipeline {
webpackProcess.send({action: constants.pipeline.init, options: {}}); webpackProcess.send({action: constants.pipeline.init, options: {}});
webpackProcess.send({action: constants.pipeline.build, file, importsList}); webpackProcess.send({action: constants.pipeline.build, file, importsList});
webpackProcess.subscribeTo('result', constants.pipeline.built, (msg) => { webpackProcess.once('result', constants.pipeline.built, (msg) => {
webpackProcess.disconnect(); webpackProcess.disconnect();
return next(msg.error); return next(msg.error);
}); });

View File

@ -41,8 +41,9 @@ class Watch {
stop() { stop() {
this.fileWatchers.forEach(fileWatcher => { this.fileWatchers.forEach(fileWatcher => {
fileWatcher.close(); if (fileWatcher.shouldClose) return;
fileWatcher = null; if (fileWatcher.isReady) fileWatcher.close();
fileWatcher.shouldClose = true;
}); });
this.fileWatchers = []; this.fileWatchers = [];
} }
@ -125,7 +126,11 @@ class Watch {
.on('add', path => changeCallback('add', path)) .on('add', path => changeCallback('add', path))
.on('change', path => changeCallback('change', path)) .on('change', path => changeCallback('change', path))
.on('unlink', path => changeCallback('remove', path)) .on('unlink', path => changeCallback('remove', path))
.on('ready', doneCallback); .once('ready', () => {
configWatcher.isReady = true;
if (configWatcher.shouldClose) configWatcher.close();
doneCallback();
});
} }
} }

View File

@ -70,13 +70,13 @@ class ProcessLauncher {
_checkSubscriptions(msg) { _checkSubscriptions(msg) {
const messageKeys = Object.keys(msg); const messageKeys = Object.keys(msg);
const subscriptionsKeys = Object.keys(this.subscriptions); const subscriptionsKeys = Object.keys(this.subscriptions);
let subscriptions; let subscriptionsForKey;
let messageKey; let messageKey;
// Find if the message contains a key that we are subscribed to // Find if the message contains a key that we are subscribed to
messageKeys.some(_messageKey => { messageKeys.some(_messageKey => {
return subscriptionsKeys.some(subscriptionKey => { return subscriptionsKeys.some(subscriptionKey => {
if (_messageKey === subscriptionKey) { if (_messageKey === subscriptionKey) {
subscriptions = this.subscriptions[subscriptionKey]; subscriptionsForKey = this.subscriptions[subscriptionKey];
messageKey = _messageKey; messageKey = _messageKey;
return true; return true;
} }
@ -84,20 +84,28 @@ class ProcessLauncher {
}); });
}); });
if (subscriptions) { if (subscriptionsForKey) {
let subscription;
// Find if we are subscribed to one of the values // Find if we are subscribed to one of the values
subscriptions.some(sub => { let subsIndex = [];
const subscriptionsForValue = subscriptionsForKey.filter((sub, index) => {
if (msg[messageKey] === sub.value) { if (msg[messageKey] === sub.value) {
subscription = sub; subsIndex.push(index);
return true; return true;
} }
return false; return false;
}); });
if (subscription) { if (subscriptionsForValue.length) {
// We are subscribed to that message, call the callback // We are subscribed to that message, call the callback
subscriptionsForValue.forEach((subscription, index) => {
subscription.callback(msg); subscription.callback(msg);
if (subscription.once) {
// Called only once, we can remove it
subscription = null;
this.subscriptions[messageKey].splice(subsIndex[index], 1);
}
});
} }
} }
} }
@ -109,7 +117,7 @@ class ProcessLauncher {
* @param {Function} callback callback(response) * @param {Function} callback callback(response)
* @return {void} * @return {void}
*/ */
subscribeTo(key, value, callback) { on(key, value, callback) {
if (this.subscriptions[key]) { if (this.subscriptions[key]) {
this.subscriptions[key].push({value, callback}); this.subscriptions[key].push({value, callback});
return; return;
@ -117,6 +125,22 @@ class ProcessLauncher {
this.subscriptions[key] = [{value, callback}]; this.subscriptions[key] = [{value, callback}];
} }
/**
* Same as .on, but only triggers once
* @param {String} key Message key to subscribe to
* @param {String} value Value that the above key must have for the callback to be called
* @param {Function} callback callback(response)
* @return {void}
*/
once(key, value, callback) {
const obj = {value, callback, once: true};
if (this.subscriptions[key]) {
this.subscriptions[key].push(obj);
return;
}
this.subscriptions[key] = [obj];
}
/** /**
* Unsubscribes from a previously subscribed key-value pair (or key if no value) * Unsubscribes from a previously subscribed key-value pair (or key if no value)
* @param {String} key Message key to unsubscribe * @param {String} key Message key to unsubscribe

View File

@ -1,14 +1,11 @@
/*global describe, it, before*/ /*global describe, it*/
const assert = require('assert'); const assert = require('assert');
const sinon = require('sinon'); const sinon = require('sinon');
const Provider = require('../lib/contracts/provider'); const AccountParser = require('../lib/contracts/accountParser');
let TestLogger = require('../lib/tests/test_logger.js'); let TestLogger = require('../lib/tests/test_logger.js');
describe('embark.provider', function () { describe('embark.AccountParser', function () {
describe('#getAccount', function () { describe('#getAccount', function () {
let provider;
before(() => {
const web3 = { const web3 = {
eth: { eth: {
accounts: { accounts: {
@ -16,29 +13,25 @@ describe('embark.provider', function () {
return {key}; return {key};
}) })
} }
},
utils: {
isHexStrict: sinon.stub().returns(true)
} }
}; };
const testLogger = new TestLogger({});
provider = new Provider({
accountsConfig: [],
logger: new TestLogger({}),
web3Endpoint: 'http:localhost:555',
web3
});
});
it('should return one account with the key', function () { it('should return one account with the key', function () {
const account = provider.getAccount({ const account = AccountParser.getAccount({
privateKey: 'myKey' privateKey: 'myKey'
}); }, web3, testLogger);
assert.deepEqual(account, {key: '0xmyKey'}); assert.deepEqual(account, {key: '0xmyKey'});
}); });
it('should return two accounts from the keys in the file', function () { it('should return two accounts from the keys in the file', function () {
const account = provider.getAccount({ const account = AccountParser.getAccount({
privateKeyFile: 'test/keyFiles/twoKeys' privateKeyFile: 'test/keyFiles/twoKeys'
}); }, web3, testLogger);
assert.deepEqual(account, [ assert.deepEqual(account, [
{key: '0xkey1'}, {key: '0xkey1'},
@ -47,20 +40,19 @@ describe('embark.provider', function () {
}); });
it('should return one account from the mnemonic', function () { it('should return one account from the mnemonic', function () {
const account = provider.getAccount({ const account = AccountParser.getAccount({
mnemonic: 'example exile argue silk regular smile grass bomb merge arm assist farm' mnemonic: 'example exile argue silk regular smile grass bomb merge arm assist farm'
}); }, web3, testLogger);
assert.deepEqual(account, assert.deepEqual(account,
[{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}]); [{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}]);
}); });
it('should return two accounts from the mnemonic using numAddresses', function () { it('should return two accounts from the mnemonic using numAddresses', function () {
const account = provider.getAccount({ const account = AccountParser.getAccount({
mnemonic: 'example exile argue silk regular smile grass bomb merge arm assist farm', mnemonic: 'example exile argue silk regular smile grass bomb merge arm assist farm',
numAddresses: 2 numAddresses: 2
}); }, web3, testLogger);
assert.deepEqual(account, assert.deepEqual(account,
[ [
@ -70,9 +62,9 @@ describe('embark.provider', function () {
}); });
it('should return nothing with bad config', function () { it('should return nothing with bad config', function () {
const account = provider.getAccount({ const account = AccountParser.getAccount({
badConfig: 'not working' badConfig: 'not working'
}); }, web3, testLogger);
assert.strictEqual(account, null); assert.strictEqual(account, null);
}); });

View File

@ -13,11 +13,19 @@ let readFile = function(file) {
return new File({filename: file, type: File.types.dapp_file, path: file}); return new File({filename: file, type: File.types.dapp_file, path: file});
}; };
const currentSolcVersion = require('../package.json').dependencies.solc;
const TestEvents = {
request: (cmd, cb) => {
cb(currentSolcVersion);
}
};
describe('embark.Contracts', function() { describe('embark.Contracts', function() {
this.timeout(0); this.timeout(0);
describe('simple', function() { describe('simple', function() {
let plugins = new Plugins({ let plugins = new Plugins({
logger: new TestLogger({}) logger: new TestLogger({}),
events: TestEvents
}); });
plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']}); plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']});
@ -99,7 +107,8 @@ describe('embark.Contracts', function() {
describe('config with contract instances', function() { describe('config with contract instances', function() {
let plugins = new Plugins({ let plugins = new Plugins({
logger: new TestLogger({}) logger: new TestLogger({}),
events: TestEvents
}); });
plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']}); plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']});

View File

@ -14,14 +14,14 @@ describe('ProcessWrapper', () => {
}); });
}); });
describe('subscribeTo', () => { describe('on', () => {
beforeEach(() => { beforeEach(() => {
processLauncher.subscriptions = {}; processLauncher.subscriptions = {};
}); });
it('should create an array for the key value', function () { it('should create an array for the key value', function () {
processLauncher.subscribeTo('test', 'value', 'myCallback'); processLauncher.on('test', 'value', 'myCallback');
assert.deepEqual(processLauncher.subscriptions, { assert.deepEqual(processLauncher.subscriptions, {
"test": [ "test": [
{ {
@ -33,8 +33,8 @@ describe('ProcessWrapper', () => {
}); });
it('should add another value to the key', () => { it('should add another value to the key', () => {
processLauncher.subscribeTo('test', 'value', 'myCallback'); processLauncher.on('test', 'value', 'myCallback');
processLauncher.subscribeTo('test', 'value2', 'myCallback2'); processLauncher.on('test', 'value2', 'myCallback2');
assert.deepEqual(processLauncher.subscriptions, { assert.deepEqual(processLauncher.subscriptions, {
"test": [ "test": [
{ {
@ -135,5 +135,39 @@ describe('ProcessWrapper', () => {
processLauncher._checkSubscriptions({test: 'value'}); processLauncher._checkSubscriptions({test: 'value'});
assert.strictEqual(callback.callCount, 1); assert.strictEqual(callback.callCount, 1);
}); });
it('should call the callback and remove the sub', function () {
const callback = sinon.stub();
processLauncher.subscriptions = {
"test": [
{
"callback": callback,
"value": "value",
"once": true
}
]
};
processLauncher._checkSubscriptions({test: 'value'});
assert.strictEqual(callback.callCount, 1);
assert.deepEqual(processLauncher.subscriptions, {test: []});
});
it('should call the callback twice', function () {
const callback = sinon.stub();
processLauncher.subscriptions = {
"test": [
{
"callback": callback,
"value": "value"
},
{
"callback": callback,
"value": "value"
}
]
};
processLauncher._checkSubscriptions({test: 'value'});
assert.strictEqual(callback.callCount, 2);
});
}); });
}); });