From 760bd984d863b8acbea049b77d9308d21cc3e822 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Tue, 15 May 2018 17:20:43 -0400 Subject: [PATCH 01/30] only close watcher when it's actually ready --- lib/pipeline/watch.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pipeline/watch.js b/lib/pipeline/watch.js index 910bb382..a2746716 100644 --- a/lib/pipeline/watch.js +++ b/lib/pipeline/watch.js @@ -41,8 +41,9 @@ class Watch { stop() { this.fileWatchers.forEach(fileWatcher => { - fileWatcher.close(); - fileWatcher = null; + if (fileWatcher.shouldClose) return; + if (fileWatcher.isReady) fileWatcher.close(); + fileWatcher.shouldClose = true; }); this.fileWatchers = []; } @@ -125,7 +126,11 @@ class Watch { .on('add', path => changeCallback('add', path)) .on('change', path => changeCallback('change', path)) .on('unlink', path => changeCallback('remove', path)) - .on('ready', doneCallback); + .once('ready', () => { + configWatcher.isReady = true; + if (configWatcher.shouldClose) configWatcher.close(); + doneCallback(); + }); } } From f2e52d1dbcafa3880992a13bd6c652daf7fdf8cd Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 16 May 2018 10:14:00 -0400 Subject: [PATCH 02/30] create processLauncher that launches and subscribes to process --- lib/i18n/locales/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/i18n/locales/en.json b/lib/i18n/locales/en.json index c3618b9d..f2437081 100644 --- a/lib/i18n/locales/en.json +++ b/lib/i18n/locales/en.json @@ -109,5 +109,6 @@ "{{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}}", "downloading {{packageName}} {{version}}....": "downloading {{packageName}} {{version}}....", "Swarm node is offline...": "Swarm node is offline...", - "Swarm node detected...": "Swarm node detected..." + "Swarm node detected...": "Swarm node detected...", + "file not found, creating it...": "file not found, creating it..." } From c94d8e9f9167a29e60106592a6f0e362f309ccdd Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Wed, 16 May 2018 18:09:56 -0400 Subject: [PATCH 03/30] update old solc process to new process wrapper --- lib/modules/solidity/solcP.js | 61 ++++++++++++++++++++++------------- lib/modules/solidity/solcW.js | 37 ++++++++++----------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/lib/modules/solidity/solcP.js b/lib/modules/solidity/solcP.js index 2beb3305..a5c19577 100644 --- a/lib/modules/solidity/solcP.js +++ b/lib/modules/solidity/solcP.js @@ -1,41 +1,58 @@ -let solc; - const fs = require('fs-extra'); const path = require('path'); const constants = require('../../constants'); const Utils = require('../../utils/utils'); -function findImports(filename) { - if (filename.startsWith('http') || filename.startsWith('git')) { - const fileObj = Utils.getExternalContractUrl(filename); - filename = fileObj.filePath; +const ProcessWrapper = require('../../process/processWrapper'); + +class SolcProcess extends ProcessWrapper { + + findImports(filename) { + if (filename.startsWith('http') || filename.startsWith('git')) { + const fileObj = Utils.getExternalContractUrl(filename); + filename = fileObj.filePath; + } + if (fs.existsSync(filename)) { + return {contents: fs.readFileSync(filename).toString()}; + } + if (fs.existsSync(path.join('./node_modules/', filename))) { + return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; + } + if (fs.existsSync(path.join(constants.httpContractsDirectory, filename))) { + return {contents: fs.readFileSync(path.join('./.embark/contracts', filename)).toString()}; + } + return {error: 'File not found'}; } - if (fs.existsSync(filename)) { - return {contents: fs.readFileSync(filename).toString()}; + + loadCompiler(solcLocation) { + this.solc = require(solcLocation); } - if (fs.existsSync(path.join('./node_modules/', filename))) { - return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; + + 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); } - if (fs.existsSync(path.join(constants.httpContractsDirectory, filename))) { - return {contents: fs.readFileSync(path.join('./.embark/contracts', filename)).toString()}; - } - return {error: 'File not found'}; + } +let solcProcess; + process.on('message', function (msg) { + if (msg.action === "init") { + solcProcess = new SolcProcess(msg.options); + return process.send({result: "initiated"}); + } + if (msg.action === 'loadCompiler') { - solc = require(msg.solcLocation); + solcProcess.loadCompiler(msg.requirePath); process.send({result: "loadedCompiler"}); } if (msg.action === 'compile') { - // TODO: only available in 0.4.11; need to make versions warn about this - let output = solc.compileStandardWrapper(JSON.stringify(msg.jsonObj), findImports); - process.send({result: "compilation", output: output}); + solcProcess.compile(msg.jsonObj, (output) => { + process.send({result: "compilation", output: output}); + }); } }); -process.on('exit', function () { - process.exit(0); -}); - diff --git a/lib/modules/solidity/solcW.js b/lib/modules/solidity/solcW.js index 70a43433..017de6f5 100644 --- a/lib/modules/solidity/solcW.js +++ b/lib/modules/solidity/solcW.js @@ -1,58 +1,59 @@ let utils = require('../../utils/utils.js'); let fs = require('../../core/fs.js'); -let solcProcess; -let compilerLoaded = false; let currentSolcVersion = require('../../../package.json').dependencies.solc; +const ProcessLauncher = require('../../process/processLauncher'); class SolcW { constructor(options) { this.logger = options.logger; this.events = options.events; + this.compilerLoaded = false; + this.solcProcess = null; } load_compiler(done) { const self = this; - if (compilerLoaded) { + if (this.compilerLoaded) { done(); } - solcProcess = require('child_process').fork(utils.joinPath(__dirname, '/solcP.js')); - solcProcess.once('message', function (msg) { - if (msg.result !== 'loadedCompiler') { - return; - } - compilerLoaded = true; + this.solcProcess = new ProcessLauncher({ + modulePath: utils.joinPath(__dirname, 'solcP.js'), + logger: self.logger, + events: self.events + }); + this.solcProcess.send({action: "init", options: {}}); + + this.solcProcess.subscribeTo('result', 'loadedCompiler', () => { + self.compilerLoaded = true; done(); }); this.events.request("version:get:solc", function(solcVersion) { if (solcVersion === currentSolcVersion) { - solcProcess.send({action: 'loadCompiler', solcLocation: 'solc'}); + self.solcProcess.send({action: 'loadCompiler', requirePath: 'solc'}); } else { self.events.request("version:getPackageLocation", "solc", solcVersion, function(err, location) { if (err) { return done(err); } let requirePath = fs.dappPath(location); - solcProcess.send({action: 'loadCompiler', solcLocation: requirePath}); + self.solcProcess.send({action: 'loadCompiler', requirePath: requirePath}); }); - } }); } isCompilerLoaded() { - return (compilerLoaded === true); + return (this.compilerLoaded === true); } compile(jsonObj, done) { - solcProcess.once('message', function (msg) { - if (msg.result !== 'compilation') { - return; - } + this.solcProcess.subscribeTo('result', 'compilation', (msg) => { done(JSON.parse(msg.output)); }); - solcProcess.send({action: 'compile', jsonObj: jsonObj}); + + this.solcProcess.send({action: 'compile', jsonObj: jsonObj}); } } From bc681a5b4f3b5d51ed2045ca31b3cafb2994a0d1 Mon Sep 17 00:00:00 2001 From: Natacha De la Rosa Date: Thu, 17 May 2018 22:21:41 -0400 Subject: [PATCH 04/30] [FIX #421] Add Spanish Translation to embark added spanish translation to Emabrk. --- lib/i18n/locales/es.json | 366 +++++++++++++++++++-------------------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/lib/i18n/locales/es.json b/lib/i18n/locales/es.json index dd0143d8..59910a4c 100644 --- a/lib/i18n/locales/es.json +++ b/lib/i18n/locales/es.json @@ -1,188 +1,188 @@ { - "New Application": "Nova Aplicacao", - "Contract Name": "Contracto", - "Address": "Endereço", - "Status": "Estado", - "Embark Blockchain Using: %s": "Embark Blockchain esta usando o commando: %s", - "running: %s": "executando: %s", - "already initialized": "ja esta inicializado", - "create a barebones project meant only for contract development": "criar um projeto vazio destinado apenas ao desenvolvimento de contratos", - "loading solc compiler": "carregando o compilador solc", - "Welcome to Embark": "Bem-vindo ao Embark", - "possible commands are:": "comandos possíveis são:", - "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", - "instantiated web3.js object configured to the current environment": "objeto web3.js instanciado configurado para o ambiente atual", - "to immediatly exit (alias: exit)": "para sair imediatamente (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", - "create a working dapp with a SimpleStorage contract": "Cria uma dapp funcional com o contrato SimpleStorage", - "filename to output logs (default: none)": "ficheiro/arquivo para saída dos logs (predefinido: none)", - "level of logging to display": "nivel do log", - "deploy and build dapp at ": "Publica os contractos e constroi a applicacao em ", - "port to run the dev webserver (default: %s)": "porta para correr o servidor web para desenvolvimento (default: %s)", - "host to run the dev webserver (default: %s)": "host para correr o servidor web para desenvolvimento (default: %s)", - "disable the development webserver": "disativa o servidor web para desenvolvimento", - "simple mode, disables the dashboard": "modo simples, disativa o dashboard", - "no colors in case it's needed for compatbility purposes": "sem cores, em caso seja necessario para compabitilidade com a terminal", - "filename to output logs (default: %s)": "ficheiro/arquivo para os logs (predefinido: %s)", - "run dapp (default: %s)": "executa a dapp (applicacao decentralizada) (predefinido: %s)", - "Use a specific ethereum client or simulator (supported: %s)": "Usa um cliente ou simulador de ethereum específico (supportado: %s)", - "run blockchain server (default: %s)": "executa un node de blockchain (predefinido: %s)", - "run a fast ethereum rpc simulator": "executa um simulador RPC de ethereum", - "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)", - "host to run the rpc simulator (default: %s)": "host para executar servidor de rpc (predefinido: %s)", - "number of accounts (default: %s)": "numero de contas (predefinido: %s)", - "Amount of ether to assign each test account (default: %s)": "Quantidade de éter para atribuir cada conta de teste (predefinido: %s)", - "custom gas limit (default: %s)": "limite de gás (predefinido: %s)", - "run tests": "executar os testes", - "resets embarks state on this dapp including clearing cache": "recomenca o estado do Embark nesta appliacao, incluindo a cache", - "generates documentation based on the smart contracts configured": "gera documentação baseada nos contratos configurados", - "Upload your dapp to a decentralized storage": "Carrega a appliacao para armazenamento descentralizado", - "output the version number": "produz a versão actual", - "Logs": "Logs", - "Environment": "Ambiente", - "Available Services": "Serviços Disponíveis", - "Contracts": "Contratos", - "Console": "Consola", - "dashboard start": "inicia o painel de controle", - "loaded plugins": "plugins carregados", - "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.", - "assuming %s to be an interface": "assumindo que %s é uma interface", - "{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: não foi possível encontrar instancia de (instanceOf) do contrato {{parentContractName}}", - "did you mean \"%s\"?": "você quis dizer \"%s\"?", - "%s has no code associated": "%s não tem código associado", - "deploying contracts": "publicando contratos", - "running beforeDeploy plugin %s .": "executando plugin beforeDeploy %s .", - "deploying": "publicando", - "with": "com", - "gas": "gas", - "Pending": "Pendente", - "Interface or set to not deploy": "Interface ou configurado para não ser publicado", - "error deploying": "erro de publicação", - "due to error": "devido a erro", - "error deploying contracts": "erro publicando contratos", - "finished deploying contracts": "publicação de contratos concluida", - "error running afterDeploy: ": "erro executado afterDeploy: ", - "ready to watch file changes": "pronto para monitorar alterações em ficheiros/arquivos", - "Starting Server": "iniciando o servidor", - "webserver available at": "servidor web disponivel em", - "Webserver": "Servidor Web", - " already deployed at ": " já publicado em ", - "Deployed": "Publicado", - "Name must be only letters, spaces, or dashes": "O nome deve ser apenas letras, espaços ou traços", - "Name your app (default is %s)": "Nome da aplicacao (predefinido is %s)", - "Invalid name": "Nome inválido", - "unknown command": "comando desconhecido", - "did you mean": "você quis dizer", - "warning: running default config on a non-development environment": "aviso: executando a configuração padrão em um ambiente de não desenvolvimento", - "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?", - "no accounts found": "nenhuma conta encontrada", - "initializing genesis block": "inicializando o bloco de gênese", + "New Application": "Nueva Aplicación", + "Contract Name": "Nombre del Contrato", + "Address": "Dirección", + "Status": "Estado", + "Embark Blockchain Using: %s": "Embark Blockchain esta usando el comando: %s", + "running: %s": "ejecutando: %s", + "already initialized": "ya esta inicializado", + "create a barebones project meant only for contract development": "crear un proyecto vacio destinado solo para el desarrollo de contratos", + "loading solc compiler": "cargando el compilador solc", + "Welcome to Embark": "Bienvenido a Embark", + "possible commands are:": "los comandos posibles son:", + "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 el entorno actual", + "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": "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": "Crear una dapp funcional con un contrato SimpleStorage", + "filename to output logs (default: none)": "fichero/archivo para salida de los logs (predefinido: none)", + "level of logging to display": "nivel de log para mostrar", + "deploy and build dapp at ": "Publica los contractos y construye la aplicación en ", + "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 el servidor web para desarrollo (default: %s)", + "disable the development webserver": "desactiva el servidor web para desarrollo", + "simple mode, disables the dashboard": "modo simple, desactiva el dashboard", + "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)": "fichero/archivo para los logs (predefinido: %s)", + "run dapp (default: %s)": "ejecutar la dapp (applicación decentralizada) (predefinido: %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)": "ejecuta un nodo de blockchain (predefinido: %s)", + "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]", + "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 ejecutar un servidor de rpc (predefinido: %s)", + "number of accounts (default: %s)": "número de cuentas (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)": "límite de gas (predefinido: %s)", + "run tests": "ejecutar las pruebas", + "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": "genera documentación basada en los contratos inteligentes configurados", + "Upload your dapp to a decentralized storage": "Suba su dapp a un almacenamiento descentralizado", + "output the version number": "mostrar el número de versión", + "Logs": "Logs", + "Environment": "Ambiente", + "Available Services": "Servicios Disponibles", + "Contracts": "Contratos", + "Console": "Consola", + "dashboard start": "inicia el panel de control", + "loaded plugins": "plugins cargados", + "compiling solidity contracts": "Compilando contratos Solidity", + "%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": "suponiendo que %s sea una interfaz", + "{{className}}: couldn't find instanceOf contract {{parentContractName}}": "{{className}}: no se pudo encontrar la instancia (instanceOf) del contrato {{parentContractName}}", + "did you mean \"%s\"?": "querías decir \"%s\"?", + "%s has no code associated": "%s no tiene código asociado", + "deploying contracts": "publicando contratos", + "running beforeDeploy plugin %s .": "ejecutanto plugin beforeDeploy %s .", + "deploying": "publicando", + "with": "con", + "gas": "gas", + "Pending": "Pendiente", + "Interface or set to not deploy": "Interfaz o configurado para no publicar", + "error deploying": "error publicando", + "due to error": "debido a error", + "error deploying contracts": "error publicando contratos", + "finished deploying contracts": "publicación de contratos concluida", + "error running afterDeploy: ": "error ejecutando afterDeploy: ", + "ready to watch file changes": "listo para monitorear alteraciones en ficheros/archivos", + "Starting Server": "iniciando el servidor", + "webserver available at": "servidor web disponible en", + "Webserver": "Servidor Web", + " already deployed at ": " ya publicado en ", + "Deployed": "Publicado", + "Name must be only letters, spaces, or dashes": "El nombre debe ser solo letras, espacios o guiones", + "Name your app (default is %s)": "Nombre su aplicación (el valor predeterminado es %s)", + "Invalid name": "Nombre inválido", + "unknown command": "comando desconocido", + "did you mean": "querías decir", + "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?": "no se pudo encontrar el comando {{geth_bin}}; ¿Está {{client_name}} instalado o en la RUTA?", + "no accounts found": "no se encontraron cuentas", + "initializing genesis block": "inicializando bloque genesis", "rpcCorsDomain set to *": "rpcCorsDomain definido como *", - "make sure you know what you are doing": "certifique-se de saber o que está fazendo", - "warning: cors is not set": "aviso: cors não está definido", + "make sure you know what you are doing": "asegúrate de saber lo que estás haciendo", + "warning: cors is not set": "aviso: cors no está definido", "wsOrigins set to *": "wsOrigins definido como *", - "warning: wsOrigins is not set": "aviso: wsOrigins não está definido", - "reset done!": "reset feito!", - "%s is not installed on your machine": "%s não está instalado na sua máquina", - "You can install it by running: %s": "Você pode instalá-lo executando: %s", - "Initializing Embark Template....": "Inicializando Embark Template....", - "Installing packages...": "Instalando pacotes...", - "Init complete": "Init complete", - "App ready at ": "App ready at ", - "Next steps:": "Next steps:", - "open another console in the same directory and run": "open another console in the same directory and run", - "For more info go to http://embark.status.im": "For more info go to http://embark.status.im", - "%s : instanceOf is set to itself": "%s : instanceOf is set to itself", - "{{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}}", - "Error Compiling/Building contracts: ": "Error Compiling/Building contracts: ", + "warning: wsOrigins is not set": "aviso: wsOrigins no está definido", + "reset done!": "reset listo!", + "%s is not installed on your machine": "%s no está instalado en su máquina", + "You can install it by running: %s": "Puede instalarlo ejecutando: %s", + "Initializing Embark Template....": "Inicializando la plantilla de Embark....", + "Installing packages...": "Instalando paquetes...", + "Init complete": "Init completo", + "App ready at ": "Aplicación lista en ", + "Next steps:": "Próximos pasos:", + "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": "Para más información ve a http://embark.status.im", + "%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}} tiene un código asociado pero está configurado como una instancia de {{parentContractName}}", + "Error Compiling/Building contracts: ": "Error Compilando/Construyendo los contractos: ", "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", - "Embark couldn't determine which one to deploy first": "Embark couldn't determine which one to deploy first", - "{{inputName}} has not been defined for {{className}} constructor": "{{inputName}} has not been defined for {{className}} constructor", - "error deploying %s": "error deploying %s", - "executing onDeploy commands": "executing onDeploy commands", - "error executing onDeploy for ": "error executing onDeploy for ", - " does not exist": " does not exist", - "error running onDeploy: ": "error running onDeploy: ", - " exists but has been set to not deploy": " exists but has been set to not deploy", - "couldn't find a valid address for %s has it been deployed?": "couldn't find a valid address for %s has it been deployed?", - "executing: ": "executing: ", - "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", - "no account found at index": "no account found at index", - " check the config": " check the config", - "Both \"from\" and \"fromIndex\" are defined for contract": "Both \"from\" and \"fromIndex\" are defined for contract", - "Using \"from\" as deployer account.": "Using \"from\" as deployer account.", - "{{linkReference}} is too long": "{{linkReference}} is too long", - "{{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?", - "attempted to deploy %s without specifying parameters": "attempted to deploy %s without specifying parameters", - "deployed at": "deployed at", - "no contracts found": "no contracts found", - "Blockchain component is disabled in the config": "Blockchain component is disabled in the config", - "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'", - "executing": "executing", - "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", - "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 config file found at %s using default config": "no config file found at %s using default config", - "HTTP contract file not found": "HTTP contract file not found", - "contract file not found": "contract file not found", - "file not found, creating it...": "file not found, creating it...", - "No Blockchain node found": "No Blockchain node found", - "Ethereum node (version unknown)": "Ethereum node (version unknown)", - "this event is deprecated and will be removed in future versions %s": "this event is deprecated and will be removed in future versions %s", - "Error while downloading the file": "Error while downloading the file", - "Plugin {{name}} can only be loaded in the context of \"{{contextes}}\"": "Plugin {{name}} can only be loaded in the context of \"{{contextes}}\"", - "error running service check": "error running service check", - "help": "ajuda", - "quit": "sair", - "Type": "Type", - "to see the list of available commands": "to see the list of available commands", + "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 no pudo determinar cual publicar primero", + "{{inputName}} has not been defined for {{className}} constructor": "{{inputName}} no ha sido definido para el constructor de {{className}}", + "error deploying %s": "error publicando %s", + "executing onDeploy commands": "ejecutando comandos onDeploy", + "error executing onDeploy for ": "error ejecutando onDeploy para ", + " does not exist": " no existe", + "error running onDeploy: ": "error ejecutando onDeploy: ", + " 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?": "no pudo encontrar una dirección válida para %s ¿ha sido publicado?", + "executing: ": "ejecutando: ", + "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 se encontró una cuenta en index", + " check the config": " verifique la configuración", + "Both \"from\" and \"fromIndex\" are defined for contract": "Ambos \"from\" y \"fromIndex\" están definidos para el contracto", + "Using \"from\" as deployer account.": "Usando \"from\" como cuenta de implementación.", + "{{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}} necesita {{libraryName}} pero no se encontró una dirección, ¿la implementó o configuró una dirección?", + "attempted to deploy %s without specifying parameters": "intentado publicar %s sin especificar parámetros", + "deployed at": "publicado en", + "no contracts found": "no hay contractos encontrados", + "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?": "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'": "asegurese de tener un nodo o simulador Ethereum en funcionamiento. e.g '%s'", + "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": "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": "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": "archivo de configuración no encontrado en %s utilizado la configuración predefinida", + "HTTP contract file not found": "archivo de contracto HTTP no encontrado", + "contract file not found": "archivo de contracto no encontrado", + "file not found, creating it...": "archivo no encontrado, creándolo ...", + "No Blockchain node found": "No se encontró ningún nodo de Blockchain", + "Ethereum node (version unknown)": "Nodo Ethereum (versión desconocida)", + "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 descargando el archivo", + "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 al ejecutar la comprobación del servicio", + "help": "ayuda", + "quit": "salir", + "Type": "Tipo", + "to see the list of available commands": "para ver la lista de comandos disponibles", "Asset Pipeline": "Asset Pipeline", - "Ethereum node detected": "Ethereum node detected", - "Deployment Done": "Deployment Done", - "Looking for documentation? You can find it at": "A procura de Documentacao? pode encontra-la em", - "Ready": "Ready", - "tip: you can resize the terminal or disable the dashboard with": "tip: you can resize the terminal or disable the dashboard with", - "finished building": "finished building", - "Done": "Done", - "Cannot upload: {{platform}} node is not running on {{url}}.": "Cannot upload: {{platform}} node is not running on {{url}}.", - "try \"{{ipfs}}\" or \"{{swarm}}\"": "try \"{{ipfs}}\" or \"{{swarm}}\"", - "finished deploying": "finished deploying", - "finished building DApp and deploying to": "finished building DApp and deploying to", - "IPFS node detected": "IPFS node detected", - "IPFS node is offline": "IPFS node is offline", - "not found or not in the path. Guessing %s for path": "not found or not in the path. Guessing %s for path", - "adding %s to ipfs": "adding %s to ipfs", - "DApp available at": "DApp available at", - "error uploading to ipfs": "error uploading to ipfs", - "successfully uploaded to ipfs": "successfully uploaded to ipfs", - "Error while loading the content of ": "Error while loading the content of ", - "error compiling for unknown reasons": "error compiling for unknown reasons", - "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", - "Swarm node detected...": "Swarm node detected...", - "Swarm node is offline...": "Swarm node is offline...", - "deploying to swarm!": "deploying to swarm!", - "adding %s to swarm": "adding %s to swarm", - "error uploading to swarm": "error uploading to swarm", - "successfully uploaded to swarm": "successfully uploaded to swarm", - "Vyper exited with error code ": "Vyper exited with error code ", - "Execution returned no result": "Execution returned no result", - "compiling Vyper contracts": "compiling Vyper contracts", - "Webserver is offline": "Webserver is offline", - "stopping webserver": "stopping webserver", - "a webserver is already running at": "a webserver is already running at", - "no webserver is currently running": "no webserver is currently running", - "couldn't find file": "couldn't find file", - "errors found while generating": "errors found while generating", - "writing file": "escrevendo ficheiro", - "Simulator not found; Please install it with \"%s\"": "Simulator not found; Please install it with \"%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", - "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", - "terminating due to error": "terminating due to 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})", - "versions": "versions", - "versions in use": "versions in use", - "downloading {{packageName}} {{version}}....": "downloading {{packageName}} {{version}}...." -} + "Ethereum node detected": "Nodo Ethereum detectado", + "Deployment Done": "Publicación completada", + "Looking for documentation? You can find it at": "¿Buscando documentación? puede encontrarla en", + "Ready": "Listo", + "tip: you can resize the terminal or disable the dashboard with": "consejo: puede redimensionar la terminal o desactivar el tablero con", + "finished building": "construcción completada", + "Done": "Hecho", + "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}}\"": "intente \"{{ipfs}}\" o \"{{swarm}}\"", + "finished deploying": "publicación completada", + "finished building DApp and deploying to": "construcción de la DApp completada y publicada en", + "IPFS node detected": "Nodo de IPFS detectado", + "IPFS node is offline": "Nodo de IPFS no está en línea", + "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": "añadiendo %s a ipfs", + "DApp available at": "DApp disponible en", + "error uploading to ipfs": "error cargando a ipfs", + "successfully uploaded to ipfs": "cargado con éxito a ipfs", + "Error while loading the content of ": "Error al cargar el contenido de ", + "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 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...": "nodo Swarm detectado...", + "Swarm node is offline...": "el nodo de Swarm no se encuentra en línea...", + "deploying to swarm!": "publicando en swarm!", + "adding %s to swarm": "añadiendo %s a swarm", + "error uploading to swarm": "error cargando a swarm", + "successfully uploaded to swarm": "cargado exitosamente a swarm", + "Vyper exited with error code ": "Vyper salió con el código de error ", + "Execution returned no result": "La ejecución no devolvió resultados", + "compiling Vyper contracts": "compilando contractos Vyper", + "Webserver is offline": "el servidor web no se encuentra en línea", + "stopping webserver": "deteniendo el servidor web", + "a webserver is already running at": "un servidor web ya se está ejecutando en", + "no webserver is currently running": "ningún servidor web se está ejecutando actualmente", + "couldn't find file": "el archivo no pudo ser encontrado", + "errors found while generating": "errores encontrados al generar", + "writing file": "escribiendo archivo", + "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": "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": "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": "terminando debido a un error", + "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": "versiones", + "versions in use": "versiones en uso", + "downloading {{packageName}} {{version}}....": "descargando {{packageName}} {{version}}...." +} \ No newline at end of file From c2086b94ae3e1a1562191c3c80f8628a38563fa6 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 08:10:59 -0500 Subject: [PATCH 05/30] should add scroller to available services Signed-off-by: VoR0220 --- lib/dashboard/monitor.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/dashboard/monitor.js b/lib/dashboard/monitor.js index 193b2b9c..21faad20 100644 --- a/lib/dashboard/monitor.js +++ b/lib/dashboard/monitor.js @@ -270,6 +270,12 @@ class Dashboard { border: { type: "line" }, + scrollable: true, + alwaysScroll: true, + scrollbar: { + ch: " ", + inverse: true + }, style: { fg: -1, border: { From 5af4eb5b25412f792e69d8b917d6047e29a2a820 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 08:54:25 -0500 Subject: [PATCH 06/30] now profiler and other plugins will be able to benefit from undefined return output for logs only plugins Signed-off-by: VoR0220 --- lib/dashboard/console.js | 14 +++++++++++--- lib/dashboard/monitor.js | 3 ++- lib/modules/profiler/index.js | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/dashboard/console.js b/lib/dashboard/console.js index 7bdae32b..44d6dec9 100644 --- a/lib/dashboard/console.js +++ b/lib/dashboard/console.js @@ -38,22 +38,30 @@ class Console { var pluginCmds = this.plugins.getPluginsProperty('console', 'console'); for (let pluginCmd of pluginCmds) { let pluginOutput = pluginCmd.call(this, cmd, {}); - if (pluginOutput !== false && pluginOutput !== 'false') return callback(pluginOutput); + //console.log("plugin output: ", pluginOutput) + if (pluginOutput !== false && pluginOutput !== 'false') + return callback(pluginOutput); + else if (pluginOutput === undefined) + return; } - + //console.log("Do we hit the here?") let output = this.processEmbarkCmd(cmd); + console.log("Output: ", output); if (output) { return callback(output); } - + console.log("What about the here?") try { let result = RunCode.doEval(cmd); + console.log("RESULT: ", result) return callback(result); } catch (e) { if (e.message.indexOf('not defined') > 0) { + console.log("Hit here in indexOf") return callback(("error: " + e.message).red + ("\n" + __("Type") + " " + "help".bold + " " + __("to see the list of available commands")).cyan); } else { + console.log("Still hit the catch") return callback(e.message); } } diff --git a/lib/dashboard/monitor.js b/lib/dashboard/monitor.js index 21faad20..53181887 100644 --- a/lib/dashboard/monitor.js +++ b/lib/dashboard/monitor.js @@ -368,7 +368,8 @@ class Dashboard { const self = this; self.logText.log('console> '.bold.green + cmd); self.console.executeCmd(cmd, function (result) { - self.logText.log(result); + if (result !== undefined) + self.logText.log(result); if (cb) { cb(result); } diff --git a/lib/modules/profiler/index.js b/lib/modules/profiler/index.js index 763165c9..7b408d45 100644 --- a/lib/modules/profiler/index.js +++ b/lib/modules/profiler/index.js @@ -48,7 +48,7 @@ class Profiler { this.profile(contractName, contract); }); } - return false; + return; }); } } From bef490f5c72d9784f34730b3c0682ead077a6246 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 09:42:30 -0500 Subject: [PATCH 07/30] get rid of console logs and try reworking the undefined handling Signed-off-by: VoR0220 --- lib/dashboard/console.js | 10 ++-------- lib/dashboard/monitor.js | 5 ++--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/dashboard/console.js b/lib/dashboard/console.js index 44d6dec9..1472be79 100644 --- a/lib/dashboard/console.js +++ b/lib/dashboard/console.js @@ -39,29 +39,23 @@ class Console { for (let pluginCmd of pluginCmds) { let pluginOutput = pluginCmd.call(this, cmd, {}); //console.log("plugin output: ", pluginOutput) - if (pluginOutput !== false && pluginOutput !== 'false') + if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) return callback(pluginOutput); - else if (pluginOutput === undefined) - return; } //console.log("Do we hit the here?") let output = this.processEmbarkCmd(cmd); - console.log("Output: ", output); if (output) { return callback(output); } - console.log("What about the here?") + try { let result = RunCode.doEval(cmd); - console.log("RESULT: ", result) return callback(result); } catch (e) { if (e.message.indexOf('not defined') > 0) { - console.log("Hit here in indexOf") return callback(("error: " + e.message).red + ("\n" + __("Type") + " " + "help".bold + " " + __("to see the list of available commands")).cyan); } else { - console.log("Still hit the catch") return callback(e.message); } } diff --git a/lib/dashboard/monitor.js b/lib/dashboard/monitor.js index 53181887..56bcd039 100644 --- a/lib/dashboard/monitor.js +++ b/lib/dashboard/monitor.js @@ -367,9 +367,8 @@ class Dashboard { executeCmd(cmd, cb) { const self = this; self.logText.log('console> '.bold.green + cmd); - self.console.executeCmd(cmd, function (result) { - if (result !== undefined) - self.logText.log(result); + self.console.executeCmd(cmd, function (result) { + self.logText.log(result); if (cb) { cb(result); } From 28fa906bbfe1f15e9fc0cffa7a48a39dea060b0e Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 10:04:49 -0500 Subject: [PATCH 08/30] concentrate undefined logic in the plugin output Signed-off-by: VoR0220 --- lib/dashboard/console.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dashboard/console.js b/lib/dashboard/console.js index 1472be79..a88f9e94 100644 --- a/lib/dashboard/console.js +++ b/lib/dashboard/console.js @@ -38,11 +38,13 @@ class Console { var pluginCmds = this.plugins.getPluginsProperty('console', 'console'); for (let pluginCmd of pluginCmds) { let pluginOutput = pluginCmd.call(this, cmd, {}); - //console.log("plugin output: ", pluginOutput) if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) return callback(pluginOutput); + if (pluginOutput === undefined) { + return callback(""); + } } - //console.log("Do we hit the here?") + let output = this.processEmbarkCmd(cmd); if (output) { return callback(output); From 8411f36e066baf5e1b64a1d6c089278fd4cde9c3 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 10:18:00 -0500 Subject: [PATCH 09/30] trying this Signed-off-by: VoR0220 --- lib/dashboard/console.js | 7 ++----- lib/modules/profiler/index.js | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/dashboard/console.js b/lib/dashboard/console.js index a88f9e94..89fff0a0 100644 --- a/lib/dashboard/console.js +++ b/lib/dashboard/console.js @@ -38,11 +38,8 @@ class Console { var pluginCmds = this.plugins.getPluginsProperty('console', 'console'); for (let pluginCmd of pluginCmds) { let pluginOutput = pluginCmd.call(this, cmd, {}); - if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) - return callback(pluginOutput); - if (pluginOutput === undefined) { - return callback(""); - } + if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) return callback(pluginOutput); + //if (pluginOutput === undefined) return callback(""); } let output = this.processEmbarkCmd(cmd); diff --git a/lib/modules/profiler/index.js b/lib/modules/profiler/index.js index 7b408d45..a1ca78e5 100644 --- a/lib/modules/profiler/index.js +++ b/lib/modules/profiler/index.js @@ -48,7 +48,6 @@ class Profiler { this.profile(contractName, contract); }); } - return; }); } } From dc0c8c56222f48fa42b61f7f643863f57e29e21f Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 10:41:23 -0500 Subject: [PATCH 10/30] fix profiler and this is ready to go Signed-off-by: VoR0220 --- lib/modules/profiler/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/modules/profiler/index.js b/lib/modules/profiler/index.js index a1ca78e5..e78c2dcf 100644 --- a/lib/modules/profiler/index.js +++ b/lib/modules/profiler/index.js @@ -47,7 +47,9 @@ class Profiler { self.logger.info("-- profile for " + contractName); this.profile(contractName, contract); }); + return ""; } + return false; }); } } From b2e45ed95c5ffe1b30205faaa7060c7e261d8794 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 10:42:08 -0500 Subject: [PATCH 11/30] remove unneeded code line Signed-off-by: VoR0220 --- lib/dashboard/console.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dashboard/console.js b/lib/dashboard/console.js index 89fff0a0..edd3feff 100644 --- a/lib/dashboard/console.js +++ b/lib/dashboard/console.js @@ -39,7 +39,6 @@ class Console { for (let pluginCmd of pluginCmds) { let pluginOutput = pluginCmd.call(this, cmd, {}); if (pluginOutput !== false && pluginOutput !== 'false' && pluginOutput !== undefined) return callback(pluginOutput); - //if (pluginOutput === undefined) return callback(""); } let output = this.processEmbarkCmd(cmd); From fee40c893540c77989b2fb31dcf162566d1672d4 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 May 2018 10:43:56 -0500 Subject: [PATCH 12/30] remove trailing whitespace Signed-off-by: VoR0220 --- lib/dashboard/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashboard/monitor.js b/lib/dashboard/monitor.js index 56bcd039..21faad20 100644 --- a/lib/dashboard/monitor.js +++ b/lib/dashboard/monitor.js @@ -367,7 +367,7 @@ class Dashboard { executeCmd(cmd, cb) { const self = this; self.logText.log('console> '.bold.green + cmd); - self.console.executeCmd(cmd, function (result) { + self.console.executeCmd(cmd, function (result) { self.logText.log(result); if (cb) { cb(result); From d6257dcbb90c12cab9a407d12c61ca144365e8b8 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 12:58:09 -0400 Subject: [PATCH 13/30] fix contract tests --- test/contracts.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/contracts.js b/test/contracts.js index 229aa0f2..3090f416 100644 --- a/test/contracts.js +++ b/test/contracts.js @@ -13,11 +13,19 @@ let readFile = function(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() { this.timeout(0); describe('simple', function() { let plugins = new Plugins({ - logger: new TestLogger({}) + logger: new TestLogger({}), + events: TestEvents }); plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']}); @@ -99,7 +107,8 @@ describe('embark.Contracts', function() { describe('config with contract instances', function() { let plugins = new Plugins({ - logger: new TestLogger({}) + logger: new TestLogger({}), + events: TestEvents }); plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']}); From 668fd3a0647ae48c3de06b2a93b5955efde48d7c Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 13:12:54 -0400 Subject: [PATCH 14/30] add fundAccount script that keeps the user's account funded --- js/fundAccount.js | 52 ++++++++++++++++++++++++++++ lib/cmds/blockchain/blockchain.js | 5 ++- lib/cmds/blockchain/geth_commands.js | 6 ++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 js/fundAccount.js diff --git a/js/fundAccount.js b/js/fundAccount.js new file mode 100644 index 00000000..ee17938f --- /dev/null +++ b/js/fundAccount.js @@ -0,0 +1,52 @@ +/*global web3, eth*/ + +(function () { + + var workAccount = '0xDf18Cb4F2005Bc52F94E9BD6C31f7B0C6394E2C2'; + + // Blockchain process ends if Javascript ends + function keepAlive() { + setInterval(function () { + // Do nothing + }, 999999); + } + + var workAccountBalance = eth.getBalance(workAccount); + var TARGET = 15000000000000000000; + if (workAccountBalance >= TARGET) { + return keepAlive(); + } + + function getNonce() { + return web3.eth.getTransactionCount(eth.coinbase); + } + + function getGasPrice() { + return web3.eth.getGasPrice(); + } + + function sendTransaction(nonce, gasPrice) { + web3.eth.sendTransaction({ + from: eth.coinbase, + to: workAccount, + value: TARGET - workAccountBalance, + gasPrice: gasPrice, + nonce: nonce + }, function (err, _result) { + if (err) { + console.error('Error while transferring funds to user account', err); + } + }); + } + + try { + var nonce = getNonce(); + var gasPrice = getGasPrice(); + sendTransaction(nonce, gasPrice); + } catch (e) { + console.error('Error while getting nonce or gas price', e); + } + + + keepAlive(); +})(); diff --git a/lib/cmds/blockchain/blockchain.js b/lib/cmds/blockchain/blockchain.js index 4bbb68eb..840fa30b 100644 --- a/lib/cmds/blockchain/blockchain.js +++ b/lib/cmds/blockchain/blockchain.js @@ -77,6 +77,8 @@ Blockchain.prototype.run = function() { return; } let address = ''; + // copy mining script + fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true}); if (!this.isDev) { address = this.initChainAndGetAddress(); } @@ -102,9 +104,6 @@ Blockchain.prototype.initChainAndGetAddress = function() { this.datadir = '.embark/' + this.env + '/datadir'; fs.mkdirpSync(this.datadir); - // copy mining script - fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true}); - // check if an account already exists, create one if not, return address result = this.runCommand(this.client.listAccountsCommand()); if (result.output === undefined || result.output.match(/{(\w+)}/) === null || result.output.indexOf("Fatal") >= 0) { diff --git a/lib/cmds/blockchain/geth_commands.js b/lib/cmds/blockchain/geth_commands.js index 379bf54e..7f08f755 100644 --- a/lib/cmds/blockchain/geth_commands.js +++ b/lib/cmds/blockchain/geth_commands.js @@ -206,6 +206,12 @@ class GethCommands { } callback(null, ""); }, + function fundAccount(callback) { + if (self.isDev) { // TODO add config param? + return callback(null, "js .embark/" + self.env + "/js/fundAccount.js"); + } + callback(null, ""); + }, function isDev(callback) { if (self.isDev) { return callback(null, '--dev'); From c3c4518cb4c108ba3e9decf3625acb29f4f4ca76 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 13:48:39 -0400 Subject: [PATCH 15/30] move account parsing to its own module --- lib/contracts/accountParser.js | 66 ++++++++++++++++++++++++++++ lib/contracts/provider.js | 78 +++++----------------------------- 2 files changed, 77 insertions(+), 67 deletions(-) create mode 100644 lib/contracts/accountParser.js diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js new file mode 100644 index 00000000..139f3c7c --- /dev/null +++ b/lib/contracts/accountParser.js @@ -0,0 +1,66 @@ +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; + } + 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 => { + if (!key.startsWith('0x')) { + key = '0x' + key; + } + 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; diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index a5225f0e..4f89b0e2 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -1,8 +1,6 @@ const ProviderEngine = require('web3-provider-engine'); const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js'); -const bip39 = require("bip39"); -const hdkey = require('ethereumjs-wallet/hdkey'); -const fs = require('../core/fs'); +const AccountParser = require('./accountParser'); class Provider { constructor(options) { @@ -18,35 +16,18 @@ class Provider { rpcUrl: options.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.accounts = AccountParser.parseAccountsConfig(this.accountsConfig, this.web3, this.logger); + this.addresses = []; + if (this.accounts.length) { + this.accounts.forEach(account => { this.addresses.push(account.address); + this.web3.eth.accounts.wallet.add(account); }); - - 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.'); - } + 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.'); } } @@ -58,43 +39,6 @@ class Provider { this.engine.start(); } - getAccount(accountConfig) { - if (accountConfig.privateKey) { - if (!accountConfig.privateKey.startsWith('0x')) { - accountConfig.privateKey = '0x' + accountConfig.privateKey; - } - return this.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 => { - if (!key.startsWith('0x')) { - key = '0x' + key; - } - return this.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(this.web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex'))); - } - return accounts; - } - 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) { return cb(null, this.addresses); } From 59c4456206a1a00229578a14ea5e9aec2d1ceacb Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 13:52:09 -0400 Subject: [PATCH 16/30] move provide rtests to accountParser tests --- test/{provider.js => accountParser.js} | 55 +++++++++++--------------- 1 file changed, 22 insertions(+), 33 deletions(-) rename test/{provider.js => accountParser.js} (64%) diff --git a/test/provider.js b/test/accountParser.js similarity index 64% rename from test/provider.js rename to test/accountParser.js index 1fc0ebbf..f6e6e79d 100644 --- a/test/provider.js +++ b/test/accountParser.js @@ -1,44 +1,34 @@ -/*global describe, it, before*/ +/*global describe, it*/ const assert = require('assert'); const sinon = require('sinon'); -const Provider = require('../lib/contracts/provider'); +const AccountParser = require('../lib/contracts/accountParser'); let TestLogger = require('../lib/tests/test_logger.js'); -describe('embark.provider', function () { +describe('embark.AccountParser', function () { describe('#getAccount', function () { - let provider; - - before(() => { - const web3 = { - eth: { - accounts: { - privateKeyToAccount: sinon.stub().callsFake((key) => { - return {key}; - }) - } + const web3 = { + eth: { + accounts: { + privateKeyToAccount: sinon.stub().callsFake((key) => { + return {key}; + }) } - }; - - provider = new Provider({ - accountsConfig: [], - logger: new TestLogger({}), - web3Endpoint: 'http:localhost:555', - web3 - }); - }); + } + }; + const testLogger = new TestLogger({}); it('should return one account with the key', function () { - const account = provider.getAccount({ + const account = AccountParser.getAccount({ privateKey: 'myKey' - }); + }, web3, testLogger); assert.deepEqual(account, {key: '0xmyKey'}); }); it('should return two accounts from the keys in the file', function () { - const account = provider.getAccount({ + const account = AccountParser.getAccount({ privateKeyFile: 'test/keyFiles/twoKeys' - }); + }, web3, testLogger); assert.deepEqual(account, [ {key: '0xkey1'}, @@ -47,20 +37,19 @@ describe('embark.provider', 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' - }); - + }, web3, testLogger); assert.deepEqual(account, [{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}]); }); 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', numAddresses: 2 - }); + }, web3, testLogger); assert.deepEqual(account, [ @@ -70,9 +59,9 @@ describe('embark.provider', function () { }); it('should return nothing with bad config', function () { - const account = provider.getAccount({ + const account = AccountParser.getAccount({ badConfig: 'not working' - }); + }, web3, testLogger); assert.strictEqual(account, null); }); From 94f0d98e28d9127d8c51f3177c9f5ae9f846a77f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 15:32:57 -0400 Subject: [PATCH 17/30] get accounts and generate script with the right address --- js/fundAccount.js | 52 -------------------------- lib/cmds/blockchain/blockchain.js | 13 ++++--- lib/cmds/blockchain/fundAccout.js.ejs | 53 +++++++++++++++++++++++++++ lib/cmds/blockchain/geth_commands.js | 22 +++++++++-- lib/index.js | 2 +- 5 files changed, 81 insertions(+), 61 deletions(-) delete mode 100644 js/fundAccount.js create mode 100644 lib/cmds/blockchain/fundAccout.js.ejs diff --git a/js/fundAccount.js b/js/fundAccount.js deleted file mode 100644 index ee17938f..00000000 --- a/js/fundAccount.js +++ /dev/null @@ -1,52 +0,0 @@ -/*global web3, eth*/ - -(function () { - - var workAccount = '0xDf18Cb4F2005Bc52F94E9BD6C31f7B0C6394E2C2'; - - // Blockchain process ends if Javascript ends - function keepAlive() { - setInterval(function () { - // Do nothing - }, 999999); - } - - var workAccountBalance = eth.getBalance(workAccount); - var TARGET = 15000000000000000000; - if (workAccountBalance >= TARGET) { - return keepAlive(); - } - - function getNonce() { - return web3.eth.getTransactionCount(eth.coinbase); - } - - function getGasPrice() { - return web3.eth.getGasPrice(); - } - - function sendTransaction(nonce, gasPrice) { - web3.eth.sendTransaction({ - from: eth.coinbase, - to: workAccount, - value: TARGET - workAccountBalance, - gasPrice: gasPrice, - nonce: nonce - }, function (err, _result) { - if (err) { - console.error('Error while transferring funds to user account', err); - } - }); - } - - try { - var nonce = getNonce(); - var gasPrice = getGasPrice(); - sendTransaction(nonce, gasPrice); - } catch (e) { - console.error('Error while getting nonce or gas price', e); - } - - - keepAlive(); -})(); diff --git a/lib/cmds/blockchain/blockchain.js b/lib/cmds/blockchain/blockchain.js index 840fa30b..81785d1b 100644 --- a/lib/cmds/blockchain/blockchain.js +++ b/lib/cmds/blockchain/blockchain.js @@ -7,6 +7,7 @@ var GethCommands = require('./geth_commands.js'); /*eslint complexity: ["error", 35]*/ var Blockchain = function(options) { this.blockchainConfig = options.blockchainConfig; + this.accountsConfig = options.accountsConfig; this.env = options.env || 'development'; this.client = options.client; this.isDev = options.isDev; @@ -41,7 +42,8 @@ var Blockchain = function(options) { vmdebug: this.blockchainConfig.vmdebug || false, targetGasLimit: this.blockchainConfig.targetGasLimit || false, light: this.blockchainConfig.light || false, - fast: this.blockchainConfig.fast || false + fast: this.blockchainConfig.fast || false, + accountsConfig: this.accountsConfig }; if (this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') { @@ -77,8 +79,6 @@ Blockchain.prototype.run = function() { return; } let address = ''; - // copy mining script - fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true}); if (!this.isDev) { address = this.initChainAndGetAddress(); } @@ -104,6 +104,9 @@ Blockchain.prototype.initChainAndGetAddress = function() { this.datadir = '.embark/' + this.env + '/datadir'; fs.mkdirpSync(this.datadir); + // copy mining script + fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true}); + // check if an account already exists, create one if not, return address result = this.runCommand(this.client.listAccountsCommand()); if (result.output === undefined || result.output.match(/{(\w+)}/) === null || result.output.indexOf("Fatal") >= 0) { @@ -123,9 +126,9 @@ Blockchain.prototype.initChainAndGetAddress = function() { return address; }; -var BlockchainClient = function(blockchainConfig, client, env, isDev) { +var BlockchainClient = function(blockchainConfig, accountsConfig, client, env, isDev) { if (client === 'geth') { - return new Blockchain({blockchainConfig: blockchainConfig, client: GethCommands, env: env, isDev}); + return new Blockchain({blockchainConfig, accountsConfig, client: GethCommands, env, isDev}); } else { throw new Error('unknown client'); } diff --git a/lib/cmds/blockchain/fundAccout.js.ejs b/lib/cmds/blockchain/fundAccout.js.ejs new file mode 100644 index 00000000..8a979722 --- /dev/null +++ b/lib/cmds/blockchain/fundAccout.js.ejs @@ -0,0 +1,53 @@ +/*global web3, eth*/ + +(function () { + +var workAccount = '<%- accountAddress %>'; + +// Blockchain process ends if Javascript ends +function keepAlive() { + setInterval(function () { + // Just stay alive + }, 999999); +} + +var workAccountBalance = eth.getBalance(workAccount); +var TARGET = 15000000000000000000; +if (workAccountBalance >= TARGET) { + return keepAlive(); +} + +function getNonce() { + return web3.eth.getTransactionCount(eth.coinbase); +} + +function getGasPrice() { + return web3.eth.getGasPrice(); +} + +function sendTransaction(nonce, gasPrice) { + web3.eth.sendTransaction({ + from: eth.coinbase, + to: workAccount, + value: TARGET - workAccountBalance, + gasPrice: gasPrice, + nonce: nonce + }, function (err, _result) { + if (err) { + console.error('Error while transferring funds to user account', err); + } + }); +} + +try { + var nonce = getNonce(); + var gasPrice = getGasPrice(); + sendTransaction(nonce, gasPrice); +} catch (e) { + console.error('Error while getting nonce or gas price', e); +} + + +keepAlive(); + +})(); diff --git a/lib/cmds/blockchain/geth_commands.js b/lib/cmds/blockchain/geth_commands.js index 7f08f755..c2bd8e70 100644 --- a/lib/cmds/blockchain/geth_commands.js +++ b/lib/cmds/blockchain/geth_commands.js @@ -1,4 +1,7 @@ -let async = require('async'); +const async = require('async'); +const Web3 = require('web3'); +const AccountParser = require('../../contracts/accountParser'); +const fs = require('../../core/fs'); // TODO: make all of this async class GethCommands { @@ -207,8 +210,21 @@ class GethCommands { callback(null, ""); }, function fundAccount(callback) { - if (self.isDev) { // TODO add config param? - return callback(null, "js .embark/" + self.env + "/js/fundAccount.js"); + if (self.isDev && self.config.accountsConfig && self.config.accountsConfig.length) { + const accounts = AccountParser.parseAccountsConfig(self.config.accountsConfig, new Web3()); + if (accounts.length) { + const fundAccountTemplate = require('./fundAccout.js.ejs'); + const code = fundAccountTemplate({accountAddress: accounts[0].address}); + const filePath = `.embark/${self.env}/js/fundAccount.js`; + fs.writeFile(fs.dappPath(filePath), code, (err) => { + if (err) { + console.error('Failed to created the script to fund the account'); + return callback(null, ''); + } + callback(null, filePath); + }); + return; + } } callback(null, ""); }, diff --git a/lib/index.js b/lib/index.js index 00dcb5f4..6a2e7d2e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -61,7 +61,7 @@ class Embark { if(webServerConfig) blockchainConfig.wsOrigins = `http://${webServerConfig.host}:${webServerConfig.port}`; if(storageConfig) blockchainConfig.wsOrigins += `${blockchainConfig.wsOrigins.length ? ',' : ''}${storageConfig.protocol}://${storageConfig.host}:${storageConfig.port}`; } - return require('./cmds/blockchain/blockchain.js')(blockchainConfig, client, env, this.isDev(env)).run(); + return require('./cmds/blockchain/blockchain.js')(blockchainConfig, this.config.contractsConfig.deployment.accounts, client, env, this.isDev(env)).run(); } simulator(options) { From 50103a8c0246207285e338e3f848edc555360f7b Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 13:39:29 -0400 Subject: [PATCH 18/30] conflict in en.json --- lib/i18n/locales/en.json | 21 ++++++--------------- test/blockchain.js | 6 ++++-- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/i18n/locales/en.json b/lib/i18n/locales/en.json index f2437081..064f90df 100644 --- a/lib/i18n/locales/en.json +++ b/lib/i18n/locales/en.json @@ -3,7 +3,6 @@ "Contract Name": "Contract Name", "New Application": "New Application", "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", "filename to output logs (default: none)": "filename to output logs (default: none)", "level of logging to display": "level of logging to display", @@ -26,9 +25,6 @@ "custom gas limit (default: %s)": "custom gas limit (default: %s)", "run tests": "run tests", "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", "Upload your dapp to a decentralized storage": "Upload your dapp to a decentralized storage", "output the version number": "output the version number", @@ -42,12 +38,7 @@ "dashboard start": "dashboard start", "loaded plugins": "loaded plugins", "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", - "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.", "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}}", @@ -79,15 +70,15 @@ "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", "versions in use": "versions in use", + "language to use (default: en)": "language to use (default: en)", "executing": "executing", - "finished deploying": "finished deploying", "writing file": "writing file", "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", "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", "running: %s": "running: %s", "Initializing Embark Template....": "Initializing Embark Template....", @@ -110,5 +101,5 @@ "downloading {{packageName}} {{version}}....": "downloading {{packageName}} {{version}}....", "Swarm node is offline...": "Swarm node is offline...", "Swarm node detected...": "Swarm node detected...", - "file not found, creating it...": "file not found, creating it..." -} + "Ethereum node (version unknown)": "Ethereum node (version unknown)" +} \ No newline at end of file diff --git a/test/blockchain.js b/test/blockchain.js index 06957e0f..af09cdac 100644 --- a/test/blockchain.js +++ b/test/blockchain.js @@ -15,6 +15,7 @@ describe('embark.Blockchain', function () { let config = { networkType: 'custom', genesisBlock: false, + accountsConfig: {}, geth_bin: 'geth', datadir: false, mineWhenNeeded: false, @@ -40,7 +41,7 @@ describe('embark.Blockchain', function () { fast: false, light: false }; - let blockchain = new Blockchain(config, 'geth'); + let blockchain = new Blockchain(config, {}, 'geth'); assert.deepEqual(blockchain.config, config); done(); @@ -54,6 +55,7 @@ describe('embark.Blockchain', function () { genesisBlock: 'foo/bar/genesis.json', geth_bin: 'geth', datadir: '/foo/datadir/', + accountsConfig: {}, mineWhenNeeded: true, rpcHost: 'someserver', rpcPort: 12345, @@ -77,7 +79,7 @@ describe('embark.Blockchain', function () { fast: false, light: false }; - let blockchain = new Blockchain(config, 'geth'); + let blockchain = new Blockchain(config, {}, 'geth'); assert.deepEqual(blockchain.config, config); done(); From 372266418f1bea5b260f2fcd6ea49d2eb20319de Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 15:42:04 -0400 Subject: [PATCH 19/30] too many spaces --- lib/cmds/blockchain/fundAccout.js.ejs | 1 - lib/contracts/accountParser.js | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/cmds/blockchain/fundAccout.js.ejs b/lib/cmds/blockchain/fundAccout.js.ejs index 8a979722..3213f1e6 100644 --- a/lib/cmds/blockchain/fundAccout.js.ejs +++ b/lib/cmds/blockchain/fundAccout.js.ejs @@ -47,7 +47,6 @@ try { console.error('Error while getting nonce or gas price', e); } - keepAlive(); })(); diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js index 139f3c7c..f2f56f8d 100644 --- a/lib/contracts/accountParser.js +++ b/lib/contracts/accountParser.js @@ -2,7 +2,6 @@ const bip39 = require("bip39"); const hdkey = require('ethereumjs-wallet/hdkey'); const fs = require('../core/fs'); - class AccountParser { static parseAccountsConfig(accountsConfig, web3, logger) { let accounts = []; From 418c55851bd337d4d5cad85f97f18c0cde15017f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 17 May 2018 15:45:43 -0400 Subject: [PATCH 20/30] remove warning when dev --- lib/contracts/provider.js | 4 ---- lib/core/engine.js | 1 - 2 files changed, 5 deletions(-) diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index 4f89b0e2..93a2746c 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -8,7 +8,6 @@ class Provider { this.web3 = options.web3; this.accountsConfig = options.accountsConfig; this.logger = options.logger; - this.isDev = options.isDev; this.engine = new ProviderEngine(); this.asyncMethods = {}; @@ -26,9 +25,6 @@ class Provider { 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 diff --git a/lib/core/engine.js b/lib/core/engine.js index 18bb6682..ab945664 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -283,7 +283,6 @@ class Engine { web3: this.web3, accountsConfig: this.config.contractsConfig.deployment.accounts, logger: this.logger, - isDev: this.isDev, web3Endpoint }; this.web3.setProvider(new Provider(providerOptions)); From 6c8653ef098824b6fdea76a8f91fd6406ec6d1c9 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 09:25:44 -0400 Subject: [PATCH 21/30] move code to front end. funds on provider start --- lib/cmds/blockchain/fundAccout.js.ejs | 52 ------------------- lib/cmds/blockchain/geth_commands.js | 22 -------- lib/contracts/fundAccount.js | 72 +++++++++++++++++++++++++++ lib/contracts/provider.js | 61 ++++++++++++++++------- lib/core/engine.js | 57 +++++++++++++-------- 5 files changed, 150 insertions(+), 114 deletions(-) delete mode 100644 lib/cmds/blockchain/fundAccout.js.ejs create mode 100644 lib/contracts/fundAccount.js diff --git a/lib/cmds/blockchain/fundAccout.js.ejs b/lib/cmds/blockchain/fundAccout.js.ejs deleted file mode 100644 index 3213f1e6..00000000 --- a/lib/cmds/blockchain/fundAccout.js.ejs +++ /dev/null @@ -1,52 +0,0 @@ -/*global web3, eth*/ - -(function () { - -var workAccount = '<%- accountAddress %>'; - -// Blockchain process ends if Javascript ends -function keepAlive() { - setInterval(function () { - // Just stay alive - }, 999999); -} - -var workAccountBalance = eth.getBalance(workAccount); -var TARGET = 15000000000000000000; -if (workAccountBalance >= TARGET) { - return keepAlive(); -} - -function getNonce() { - return web3.eth.getTransactionCount(eth.coinbase); -} - -function getGasPrice() { - return web3.eth.getGasPrice(); -} - -function sendTransaction(nonce, gasPrice) { - web3.eth.sendTransaction({ - from: eth.coinbase, - to: workAccount, - value: TARGET - workAccountBalance, - gasPrice: gasPrice, - nonce: nonce - }, function (err, _result) { - if (err) { - console.error('Error while transferring funds to user account', err); - } - }); -} - -try { - var nonce = getNonce(); - var gasPrice = getGasPrice(); - sendTransaction(nonce, gasPrice); -} catch (e) { - console.error('Error while getting nonce or gas price', e); -} - -keepAlive(); - -})(); diff --git a/lib/cmds/blockchain/geth_commands.js b/lib/cmds/blockchain/geth_commands.js index c2bd8e70..b05ada7a 100644 --- a/lib/cmds/blockchain/geth_commands.js +++ b/lib/cmds/blockchain/geth_commands.js @@ -1,7 +1,4 @@ const async = require('async'); -const Web3 = require('web3'); -const AccountParser = require('../../contracts/accountParser'); -const fs = require('../../core/fs'); // TODO: make all of this async class GethCommands { @@ -209,25 +206,6 @@ class GethCommands { } callback(null, ""); }, - function fundAccount(callback) { - if (self.isDev && self.config.accountsConfig && self.config.accountsConfig.length) { - const accounts = AccountParser.parseAccountsConfig(self.config.accountsConfig, new Web3()); - if (accounts.length) { - const fundAccountTemplate = require('./fundAccout.js.ejs'); - const code = fundAccountTemplate({accountAddress: accounts[0].address}); - const filePath = `.embark/${self.env}/js/fundAccount.js`; - fs.writeFile(fs.dappPath(filePath), code, (err) => { - if (err) { - console.error('Failed to created the script to fund the account'); - return callback(null, ''); - } - callback(null, filePath); - }); - return; - } - } - callback(null, ""); - }, function isDev(callback) { if (self.isDev) { return callback(null, '--dev'); diff --git a/lib/contracts/fundAccount.js b/lib/contracts/fundAccount.js new file mode 100644 index 00000000..cb9baade --- /dev/null +++ b/lib/contracts/fundAccount.js @@ -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; diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index 93a2746c..8b621262 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -1,38 +1,63 @@ const ProviderEngine = require('web3-provider-engine'); const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js'); +const async = require('async'); const AccountParser = require('./accountParser'); +const fundAccount = require('./fundAccount'); + +const NO_ACCOUNTS = 'noAccounts'; class Provider { constructor(options) { - const self = this; this.web3 = options.web3; this.accountsConfig = options.accountsConfig; + this.web3Endpoint = options.web3Endpoint; this.logger = options.logger; this.engine = new ProviderEngine(); this.asyncMethods = {}; + } - this.engine.addProvider(new RpcSubprovider({ - rpcUrl: options.web3Endpoint + startProvider(callback) { + const self = this; + self.engine.addProvider(new RpcSubprovider({ + rpcUrl: self.web3Endpoint })); - this.accounts = AccountParser.parseAccountsConfig(this.accountsConfig, this.web3, this.logger); - this.addresses = []; - if (this.accounts.length) { - this.accounts.forEach(account => { - this.addresses.push(account.address); - this.web3.eth.accounts.wallet.add(account); - }); - this.asyncMethods = { - eth_accounts: self.eth_accounts.bind(this) - }; - } - // network connectivity error - this.engine.on('error', (err) => { + self.engine.on('error', (err) => { // report connectivity errors - this.logger.error(err.stack); + self.logger.error(err.stack); + }); + + self.engine.start(); + self.web3.setProvider(self); + + 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); + } + async.each(self.accounts, (account, eachCb) => { + fundAccount(self.web3, account.address, eachCb); + }, next); + }, + function populateWeb3Wallet(next) { + self.accounts.forEach(account => { + self.addresses.push(account.address); + self.web3.eth.accounts.wallet.add(account); + }); + self.asyncMethods = { + eth_accounts: self.eth_accounts.bind(self) + }; + next(); + } + ], function (err) { + if (err && err !== NO_ACCOUNTS) { + self.logger.error((err)); + } + callback(); }); - this.engine.start(); } eth_accounts(payload, cb) { diff --git a/lib/core/engine.js b/lib/core/engine.js index ab945664..c59e9566 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -275,6 +275,7 @@ class Engine { web3Service(options) { let self = this; this.web3 = options.web3; + let provider; if (this.web3 === undefined) { this.web3 = new Web3(); if (this.config.contractsConfig.deployment.type === "rpc") { @@ -285,43 +286,55 @@ class Engine { logger: this.logger, web3Endpoint }; - this.web3.setProvider(new Provider(providerOptions)); + provider = new Provider(providerOptions); } else { throw new Error("contracts config error: unknown deployment type " + this.config.contractsConfig.deployment.type); } } - self.servicesMonitor.addCheck('Ethereum', function (cb) { - if (self.web3.currentProvider === undefined) { - return cb({name: __("No Blockchain node found"), status: 'off'}); + async.waterfall([ + function (next) { + if (!provider) { + return next(); + } + provider.startProvider(next); } - - self.web3.eth.getAccounts(function(err, _accounts) { - if (err) { + ], function (err) { + if (err) { + console.error(err); + } + self.servicesMonitor.addCheck('Ethereum', function (cb) { + if (self.web3.currentProvider === undefined) { return cb({name: __("No Blockchain node found"), status: 'off'}); } - // TODO: web3_clientVersion method is currently not implemented in web3.js 1.0 - self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => { + self.web3.eth.getAccounts(function(err, _accounts) { if (err) { - return cb({name: __("Ethereum node (version unknown)"), status: 'on'}); + return cb({name: __("No Blockchain node found"), status: 'off'}); } - if (version.indexOf("/") < 0) { - return cb({name: version, status: 'on'}); - } - let nodeName = version.split("/")[0]; - let versionNumber = version.split("/")[1].split("-")[0]; - let name = nodeName + " " + versionNumber + " (Ethereum)"; - return cb({name: name, status: 'on'}); + // TODO: web3_clientVersion method is currently not implemented in web3.js 1.0 + self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => { + if (err) { + return cb({name: __("Ethereum node (version unknown)"), status: 'on'}); + } + if (version.indexOf("/") < 0) { + return cb({name: version, status: 'on'}); + } + let nodeName = version.split("/")[0]; + let versionNumber = version.split("/")[1].split("-")[0]; + let name = nodeName + " " + versionNumber + " (Ethereum)"; + + return cb({name: name, status: 'on'}); + }); }); }); - }); - this.registerModule('whisper', { - addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor), - communicationConfig: this.config.communicationConfig, - web3: this.web3 + self.registerModule('whisper', { + addCheck: self.servicesMonitor.addCheck.bind(self.servicesMonitor), + communicationConfig: self.config.communicationConfig, + web3: self.web3 + }); }); } From a1e3c741a04c239117bf778dd07dc10147a79535 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 09:34:59 -0400 Subject: [PATCH 22/30] remove remaning of accounts config in blockchain --- lib/cmds/blockchain/blockchain.js | 8 +++----- lib/i18n/locales/en.json | 5 ++++- lib/index.js | 2 +- test/blockchain.js | 10 ++++------ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/cmds/blockchain/blockchain.js b/lib/cmds/blockchain/blockchain.js index 81785d1b..56b43b5a 100644 --- a/lib/cmds/blockchain/blockchain.js +++ b/lib/cmds/blockchain/blockchain.js @@ -7,7 +7,6 @@ var GethCommands = require('./geth_commands.js'); /*eslint complexity: ["error", 35]*/ var Blockchain = function(options) { this.blockchainConfig = options.blockchainConfig; - this.accountsConfig = options.accountsConfig; this.env = options.env || 'development'; this.client = options.client; this.isDev = options.isDev; @@ -42,8 +41,7 @@ var Blockchain = function(options) { vmdebug: this.blockchainConfig.vmdebug || false, targetGasLimit: this.blockchainConfig.targetGasLimit || false, light: this.blockchainConfig.light || false, - fast: this.blockchainConfig.fast || false, - accountsConfig: this.accountsConfig + fast: this.blockchainConfig.fast || false }; if (this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') { @@ -126,9 +124,9 @@ Blockchain.prototype.initChainAndGetAddress = function() { return address; }; -var BlockchainClient = function(blockchainConfig, accountsConfig, client, env, isDev) { +var BlockchainClient = function(blockchainConfig, client, env, isDev) { if (client === 'geth') { - return new Blockchain({blockchainConfig, accountsConfig, client: GethCommands, env, isDev}); + return new Blockchain({blockchainConfig, client: GethCommands, env, isDev}); } else { throw new Error('unknown client'); } diff --git a/lib/i18n/locales/en.json b/lib/i18n/locales/en.json index 064f90df..81f2aa87 100644 --- a/lib/i18n/locales/en.json +++ b/lib/i18n/locales/en.json @@ -101,5 +101,8 @@ "downloading {{packageName}} {{version}}....": "downloading {{packageName}} {{version}}....", "Swarm node is offline...": "Swarm node is offline...", "Swarm node detected...": "Swarm node detected...", - "Ethereum node (version unknown)": "Ethereum node (version unknown)" + "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'" } \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 6a2e7d2e..00dcb5f4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -61,7 +61,7 @@ class Embark { if(webServerConfig) blockchainConfig.wsOrigins = `http://${webServerConfig.host}:${webServerConfig.port}`; if(storageConfig) blockchainConfig.wsOrigins += `${blockchainConfig.wsOrigins.length ? ',' : ''}${storageConfig.protocol}://${storageConfig.host}:${storageConfig.port}`; } - return require('./cmds/blockchain/blockchain.js')(blockchainConfig, this.config.contractsConfig.deployment.accounts, client, env, this.isDev(env)).run(); + return require('./cmds/blockchain/blockchain.js')(blockchainConfig, client, env, this.isDev(env)).run(); } simulator(options) { diff --git a/test/blockchain.js b/test/blockchain.js index af09cdac..bcb48d08 100644 --- a/test/blockchain.js +++ b/test/blockchain.js @@ -15,7 +15,6 @@ describe('embark.Blockchain', function () { let config = { networkType: 'custom', genesisBlock: false, - accountsConfig: {}, geth_bin: 'geth', datadir: false, mineWhenNeeded: false, @@ -32,7 +31,7 @@ describe('embark.Blockchain', function () { whisper: true, account: {}, bootnodes: "", - wsApi: [ "eth", "web3", "net", "shh" ], + wsApi: ["eth", "web3", "net", "shh"], wsHost: "localhost", wsOrigins: false, wsPort: 8546, @@ -41,7 +40,7 @@ describe('embark.Blockchain', function () { fast: false, light: false }; - let blockchain = new Blockchain(config, {}, 'geth'); + let blockchain = new Blockchain(config, 'geth'); assert.deepEqual(blockchain.config, config); done(); @@ -55,7 +54,6 @@ describe('embark.Blockchain', function () { genesisBlock: 'foo/bar/genesis.json', geth_bin: 'geth', datadir: '/foo/datadir/', - accountsConfig: {}, mineWhenNeeded: true, rpcHost: 'someserver', rpcPort: 12345, @@ -70,7 +68,7 @@ describe('embark.Blockchain', function () { whisper: false, account: {}, bootnodes: "", - wsApi: [ "eth", "web3", "net", "shh" ], + wsApi: ["eth", "web3", "net", "shh"], wsHost: "localhost", wsOrigins: false, wsPort: 8546, @@ -79,7 +77,7 @@ describe('embark.Blockchain', function () { fast: false, light: false }; - let blockchain = new Blockchain(config, {}, 'geth'); + let blockchain = new Blockchain(config, 'geth'); assert.deepEqual(blockchain.config, config); done(); From 09cdab7e2b2e7d40ec260e3c49aaeb65b86ee08c Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 09:46:39 -0400 Subject: [PATCH 23/30] fund account only in dev --- lib/contracts/provider.js | 4 ++++ lib/core/engine.js | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index 8b621262..04be7501 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -12,6 +12,7 @@ class Provider { this.accountsConfig = options.accountsConfig; this.web3Endpoint = options.web3Endpoint; this.logger = options.logger; + this.isDev = options.isDev; this.engine = new ProviderEngine(); this.asyncMethods = {}; } @@ -38,6 +39,9 @@ class Provider { if (!self.accounts.length) { return next(NO_ACCOUNTS); } + if (!self.isDev) { + return next(); + } async.each(self.accounts, (account, eachCb) => { fundAccount(self.web3, account.address, eachCb); }, next); diff --git a/lib/core/engine.js b/lib/core/engine.js index c59e9566..5885d27e 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -40,7 +40,7 @@ class Engine { }, 0); if (this.interceptLogs || this.interceptLogs === undefined) { - this.doInterceptLogs(); + // this.doInterceptLogs(); } } @@ -284,6 +284,7 @@ class Engine { web3: this.web3, accountsConfig: this.config.contractsConfig.deployment.accounts, logger: this.logger, + isDev: this.isDev, web3Endpoint }; provider = new Provider(providerOptions); From 4c17aa9d400a669b1004a0bff8438dc7dfb01c25 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 13:27:01 -0400 Subject: [PATCH 24/30] fix some PR comments --- lib/cmds/blockchain/blockchain.js | 1 + lib/contracts/accountParser.js | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/cmds/blockchain/blockchain.js b/lib/cmds/blockchain/blockchain.js index 56b43b5a..5598e91d 100644 --- a/lib/cmds/blockchain/blockchain.js +++ b/lib/cmds/blockchain/blockchain.js @@ -125,6 +125,7 @@ Blockchain.prototype.initChainAndGetAddress = function() { }; var BlockchainClient = function(blockchainConfig, client, env, isDev) { + // TODO add other clients at some point if (client === 'geth') { return new Blockchain({blockchainConfig, client: GethCommands, env, isDev}); } else { diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js index f2f56f8d..e2460bd6 100644 --- a/lib/contracts/accountParser.js +++ b/lib/contracts/accountParser.js @@ -29,15 +29,23 @@ class AccountParser { 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 => { + 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); }); } From 6c1d9d9b39f8f03f42d00e6361dc097e0aab10ff Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 13:30:12 -0400 Subject: [PATCH 25/30] rename startProvider to startWeb3Provider --- lib/contracts/provider.js | 2 +- lib/core/engine.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index 04be7501..29b5ad2a 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -17,7 +17,7 @@ class Provider { this.asyncMethods = {}; } - startProvider(callback) { + startWeb3Provider(callback) { const self = this; self.engine.addProvider(new RpcSubprovider({ rpcUrl: self.web3Endpoint diff --git a/lib/core/engine.js b/lib/core/engine.js index 5885d27e..b41736e8 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -298,7 +298,7 @@ class Engine { if (!provider) { return next(); } - provider.startProvider(next); + provider.startWeb3Provider(next); } ], function (err) { if (err) { From 46c2be16def05347cd1199ad603f0f290dd73602 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 18 May 2018 13:41:25 -0400 Subject: [PATCH 26/30] don't unnecessary reload solc --- lib/modules/solidity/index.js | 13 +++++++------ lib/modules/solidity/solcW.js | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index 46012b2b..b28fb039 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -7,6 +7,8 @@ class Solidity { this.logger = embark.logger; this.events = embark.events; this.contractDirectories = options.contractDirectories; + this.solcAlreadyLoaded = false; + this.solcW = null; embark.registerCompiler(".sol", this.compile_solidity.bind(this)); } @@ -17,7 +19,6 @@ class Solidity { } let self = this; let input = {}; - let solcW; async.waterfall([ function prepareInput(callback) { async.each(contractFiles, @@ -44,14 +45,14 @@ class Solidity { ); }, function loadCompiler(callback) { - // TODO: there ino need to load this twice - solcW = new SolcW({logger: self.logger, events: self.events}); - if (solcW.isCompilerLoaded()) { + if (self.solcAlreadyLoaded) { return callback(); } + self.solcW = new SolcW({logger: self.logger, events: self.events}); self.logger.info(__("loading solc compiler") + ".."); - solcW.load_compiler(function (err) { + self.solcW.load_compiler(function (err) { + self.solcAlreadyLoaded = true; callback(err); }); }, @@ -73,7 +74,7 @@ class Solidity { } }; - solcW.compile(jsonObj, function (output) { + self.solcW.compile(jsonObj, function (output) { if (output.errors) { for (let i=0; i { + self.solcProcess.unsubscribeTo('result', 'compilation'); done(JSON.parse(msg.output)); }); From 6702cd223141d9bc7740bba86e6f342912760d4f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 13:44:03 -0400 Subject: [PATCH 27/30] fix tests --- test/accountParser.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/accountParser.js b/test/accountParser.js index f6e6e79d..d79b002f 100644 --- a/test/accountParser.js +++ b/test/accountParser.js @@ -13,6 +13,9 @@ describe('embark.AccountParser', function () { return {key}; }) } + }, + utils: { + isHexStrict: sinon.stub().returns(true) } }; const testLogger = new TestLogger({}); From c5c00fc3b4944e03e6c1a02536ffdafa5863666f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 14:11:29 -0400 Subject: [PATCH 28/30] conflict in solcW --- lib/modules/solidity/solcW.js | 4 ++-- lib/pipeline/pipeline.js | 2 +- lib/process/processLauncher.js | 42 ++++++++++++++++++++++++++-------- test/processLauncher.js | 42 ++++++++++++++++++++++++++++++---- 4 files changed, 74 insertions(+), 16 deletions(-) diff --git a/lib/modules/solidity/solcW.js b/lib/modules/solidity/solcW.js index 78813dc3..2f389731 100644 --- a/lib/modules/solidity/solcW.js +++ b/lib/modules/solidity/solcW.js @@ -24,7 +24,7 @@ class SolcW { }); this.solcProcess.send({action: "init", options: {}}); - this.solcProcess.subscribeTo('result', 'loadedCompiler', () => { + this.solcProcess.on('result', 'loadedCompiler', () => { self.compilerLoaded = true; done(); }); @@ -50,7 +50,7 @@ class SolcW { compile(jsonObj, done) { const self = this; - this.solcProcess.subscribeTo('result', 'compilation', (msg) => { + this.solcProcess.on('result', 'compilation', (msg) => { self.solcProcess.unsubscribeTo('result', 'compilation'); done(JSON.parse(msg.output)); }); diff --git a/lib/pipeline/pipeline.js b/lib/pipeline/pipeline.js index b1129932..9143d510 100644 --- a/lib/pipeline/pipeline.js +++ b/lib/pipeline/pipeline.js @@ -80,7 +80,7 @@ class Pipeline { webpackProcess.send({action: constants.pipeline.init, options: {}}); webpackProcess.send({action: constants.pipeline.build, file, importsList}); - webpackProcess.subscribeTo('result', constants.pipeline.built, (msg) => { + webpackProcess.on('result', constants.pipeline.built, (msg) => { webpackProcess.disconnect(); return next(msg.error); }); diff --git a/lib/process/processLauncher.js b/lib/process/processLauncher.js index e58db305..18f6e68e 100644 --- a/lib/process/processLauncher.js +++ b/lib/process/processLauncher.js @@ -70,13 +70,13 @@ class ProcessLauncher { _checkSubscriptions(msg) { const messageKeys = Object.keys(msg); const subscriptionsKeys = Object.keys(this.subscriptions); - let subscriptions; + let subscriptionsForKey; let messageKey; // Find if the message contains a key that we are subscribed to messageKeys.some(_messageKey => { return subscriptionsKeys.some(subscriptionKey => { if (_messageKey === subscriptionKey) { - subscriptions = this.subscriptions[subscriptionKey]; + subscriptionsForKey = this.subscriptions[subscriptionKey]; messageKey = _messageKey; return true; } @@ -84,20 +84,28 @@ class ProcessLauncher { }); }); - if (subscriptions) { - let subscription; + if (subscriptionsForKey) { // 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) { - subscription = sub; + subsIndex.push(index); return true; } return false; }); - if (subscription) { + if (subscriptionsForValue.length) { // We are subscribed to that message, call the callback - subscription.callback(msg); + subscriptionsForValue.forEach((subscription, index) => { + 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) * @return {void} */ - subscribeTo(key, value, callback) { + on(key, value, callback) { if (this.subscriptions[key]) { this.subscriptions[key].push({value, callback}); return; @@ -117,6 +125,22 @@ class ProcessLauncher { 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) * @param {String} key Message key to unsubscribe diff --git a/test/processLauncher.js b/test/processLauncher.js index e75d2b4e..e0272be2 100644 --- a/test/processLauncher.js +++ b/test/processLauncher.js @@ -14,14 +14,14 @@ describe('ProcessWrapper', () => { }); }); - describe('subscribeTo', () => { + describe('on', () => { beforeEach(() => { processLauncher.subscriptions = {}; }); it('should create an array for the key value', function () { - processLauncher.subscribeTo('test', 'value', 'myCallback'); + processLauncher.on('test', 'value', 'myCallback'); assert.deepEqual(processLauncher.subscriptions, { "test": [ { @@ -33,8 +33,8 @@ describe('ProcessWrapper', () => { }); it('should add another value to the key', () => { - processLauncher.subscribeTo('test', 'value', 'myCallback'); - processLauncher.subscribeTo('test', 'value2', 'myCallback2'); + processLauncher.on('test', 'value', 'myCallback'); + processLauncher.on('test', 'value2', 'myCallback2'); assert.deepEqual(processLauncher.subscriptions, { "test": [ { @@ -135,5 +135,39 @@ describe('ProcessWrapper', () => { processLauncher._checkSubscriptions({test: 'value'}); 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); + }); }); }); From a7be2cda26c15e017ece651df445c4e870ac6cfa Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 14:22:58 -0400 Subject: [PATCH 29/30] convert solcw to use once --- lib/modules/solidity/solcW.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/modules/solidity/solcW.js b/lib/modules/solidity/solcW.js index 2f389731..5dd794b0 100644 --- a/lib/modules/solidity/solcW.js +++ b/lib/modules/solidity/solcW.js @@ -15,7 +15,7 @@ class SolcW { load_compiler(done) { const self = this; if (this.compilerLoaded) { - done(); + return done(); } this.solcProcess = new ProcessLauncher({ modulePath: utils.joinPath(__dirname, 'solcP.js'), @@ -24,7 +24,7 @@ class SolcW { }); this.solcProcess.send({action: "init", options: {}}); - this.solcProcess.on('result', 'loadedCompiler', () => { + this.solcProcess.once('result', 'loadedCompiler', () => { self.compilerLoaded = true; done(); }); @@ -49,9 +49,7 @@ class SolcW { } compile(jsonObj, done) { - const self = this; - this.solcProcess.on('result', 'compilation', (msg) => { - self.solcProcess.unsubscribeTo('result', 'compilation'); + this.solcProcess.once('result', 'compilation', (msg) => { done(JSON.parse(msg.output)); }); From b829643f612a6260f410bae639ff2ecee896fc23 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 18 May 2018 14:25:20 -0400 Subject: [PATCH 30/30] use once in pipeline --- lib/pipeline/pipeline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pipeline/pipeline.js b/lib/pipeline/pipeline.js index 9143d510..5bcea392 100644 --- a/lib/pipeline/pipeline.js +++ b/lib/pipeline/pipeline.js @@ -80,7 +80,7 @@ class Pipeline { webpackProcess.send({action: constants.pipeline.init, options: {}}); webpackProcess.send({action: constants.pipeline.build, file, importsList}); - webpackProcess.on('result', constants.pipeline.built, (msg) => { + webpackProcess.once('result', constants.pipeline.built, (msg) => { webpackProcess.disconnect(); return next(msg.error); });