diff --git a/lib/core/processes/processWrapper.js b/lib/core/processes/processWrapper.js index 8045a2bf..3b934a10 100644 --- a/lib/core/processes/processWrapper.js +++ b/lib/core/processes/processWrapper.js @@ -1,4 +1,4 @@ -process.on('uncaughtException', function(e) { +process.on('uncaughtException', function(e){ process.send({error: e.stack}); }); diff --git a/lib/modules/blockchain_connector/index.js b/lib/modules/blockchain_connector/index.js index e6eb06b7..9720ec12 100644 --- a/lib/modules/blockchain_connector/index.js +++ b/lib/modules/blockchain_connector/index.js @@ -1,28 +1,34 @@ const Web3 = require('web3'); const async = require('async'); const Provider = require('./provider.js'); -const utils = require('../utils/utils'); +const utils = require('../../utils/utils'); +const constants = require('../../constants'); +const embarkJsUtils = require('embarkjs').Utils; const WEB3_READY = 'web3Ready'; -class Blockchain { - constructor(options) { +// TODO: consider another name, this is the blockchain connector +class BlockchainConnector { + constructor(embark, options) { const self = this; this.plugins = options.plugins; - this.logger = options.logger; - this.events = options.events; - this.contractsConfig = options.contractsConfig; - this.blockchainConfig = options.blockchainConfig; + this.logger = embark.logger; + this.events = embark.events; + this.contractsConfig = embark.config.contractsConfig; + this.blockchainConfig = embark.config.blockchainConfig; this.web3 = options.web3; this.isDev = options.isDev; this.web3Endpoint = ''; this.isWeb3Ready = false; - this.web3StartedInProcess = false; self.events.setCommandHandler("blockchain:web3:isReady", (cb) => { cb(self.isWeb3Ready); }); + self.events.setCommandHandler("blockchain:object", (cb) => { + cb(self); + }); + if (!this.web3) { this.initWeb3(); } else { @@ -32,9 +38,19 @@ class Blockchain { this.registerRequests(); this.registerWeb3Object(); this.registerEvents(); + this.subscribeToPendingTransactions(); } - initWeb3() { + //initWeb3() { + initWeb3(cb) { + if (!cb) { + cb = function(){}; + } + if (this.isWeb3Ready) { + this.events.emit(WEB3_READY); + return cb(); + } + const self = this; this.web3 = new Web3(); @@ -60,6 +76,18 @@ class Blockchain { self.events.request("processes:launch", "blockchain", () => { self.provider.startWeb3Provider(() => { + this.web3.eth.net.getId() + .then(id => { + let networkId = self.blockchainConfig.networkId; + if (!networkId && constants.blockchain.networkIds[self.blockchainConfig.networkType]) { + networkId = constants.blockchain.networkIds[self.blockchainConfig.networkType]; + } + if (id.toString() !== networkId.toString()) { + self.logger.warn(__('Connected to a blockchain node on network {{realId}} while your config specifies {{configId}}', {realId: id, configId: networkId})); + self.logger.warn(__('Make sure you started the right blockchain node')); + } + }) + .catch(console.error); self.provider.fundAccounts(() => { self.isWeb3Ready = true; self.events.emit(WEB3_READY); @@ -204,60 +232,14 @@ class Blockchain { } deployContractFromObject(deployContractObject, params, cb) { - const self = this; - let hash; - let calledBacked = false; - - function callback(err, receipt) { - if (calledBacked) { - return; - } - if (!err && !receipt.contractAddress) { - return; // Not deployed yet. Need to wait - } - if (interval) { - clearInterval(interval); - } - calledBacked = true; - cb(err, receipt); - } - - // This interval is there to compensate for the event that sometimes doesn't get triggered when using WebSocket - // FIXME The issue somehow only happens when the blockchain node is started in the same terminal - const interval = setInterval(() => { - if (!hash) { - return; // Wait until we receive the hash - } - self.web3.eth.getTransactionReceipt(hash, (err, receipt) => { - if (!err && !receipt) { - return; // Transaction is not yet complete - } - callback(err, receipt); - }); - }, 500); - - deployContractObject.send({ + embarkJsUtils.secureSend(this.web3, deployContractObject, { from: params.from, gas: params.gas, gasPrice: params.gasPrice - }, function (err, transactionHash) { - if (err) { - return callback(err); - } - hash = transactionHash; - }).on('receipt', function (receipt) { - if (receipt.contractAddress !== undefined) { - callback(null, receipt); - } - }).then(function (_contract) { - if (!hash) { - return; // Somehow we didn't get the receipt yet... Interval will catch it - } - self.web3.eth.getTransactionReceipt(hash, callback); - }).catch(callback); + }, true, cb); } determineDefaultAccount(cb) { const self = this; - self.getAccounts(function (err, accounts) { + self.getAccounts(function(err, accounts) { if (err) { self.logger.error(err); return cb(new Error(err)); @@ -274,7 +256,20 @@ class Blockchain { // can just be a command without a callback this.events.emit("runcode:register", "web3", this.web3); } + + subscribeToPendingTransactions() { + const self = this; + this.onReady(() => { + if (self.logsSubscription) { + self.logsSubscription.unsubscribe(); + } + self.logsSubscription = self.web3.eth + .subscribe('newBlockHeaders', () => {}) + .on("data", function (blockHeader) { + self.events.emit('block:header', blockHeader); + }); + }); + } } -module.exports = Blockchain; - +module.exports = BlockchainConnector; diff --git a/lib/modules/blockchain_connector/provider.js b/lib/modules/blockchain_connector/provider.js index 22d1c77e..59b1bdb9 100644 --- a/lib/modules/blockchain_connector/provider.js +++ b/lib/modules/blockchain_connector/provider.js @@ -11,50 +11,20 @@ class Provider { this.web3Endpoint = options.web3Endpoint; this.logger = options.logger; this.isDev = options.isDev; - this.engine = new ProviderEngine(); - this.asyncMethods = {}; } startWeb3Provider(callback) { const self = this; if (this.type === 'rpc') { - self.engine.addProvider(new RpcSubprovider({ - rpcUrl: self.web3Endpoint - })); + self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint); } else if (this.type === 'ws') { - //self.engine.addProvider(new WsSubprovider({ - console.log('USing ws'); - self.addProvider(new SubscriptionSubprovider()); - self.addProvider(new WsSubprovider({ - rpcUrl: self.web3Endpoint, - origin: this.blockchainConfig.wsOrigins.split(',')[0] - })); - //self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "embark"}}); + self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "embark"}}); } else { return callback(__("contracts config error: unknown deployment type %s", this.type)); } - - // network connectivity error - self.engine.on('error', (err) => { - // report connectivity errors - self.logger.error(err); - }); - - self.engine.start(); - //self.on('error', (err) => { - // console.log('ERR', JSON.stringify(err)); - // // report connectivity errors as trace due to polling - // self.logger.trace('web3 provider error: ', err); - // self.logger.trace('stopping web3 provider due to error'); - - // // prevent continuous polling errors - // self.stop(); - //}); - - //self.web3.setProvider(self); - //self.start(); + self.web3.setProvider(self.provider); self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger); self.addresses = []; @@ -66,22 +36,16 @@ class Provider { self.addresses.push(account.address); self.web3.eth.accounts.wallet.add(account); }); - - self.realAccountFunction = self.web3.eth.getAccounts; - self.web3.eth.getAccounts = function (cb) { - if (!cb) { - cb = function () { - }; - } - return new Promise((resolve, reject) => { - self.realAccountFunction((err, accounts) => { + self.web3.eth.defaultAccount = self.addresses[0]; + const realSend = self.provider.send.bind(self.provider); + self.provider.send = function (payload, cb) { + if (payload.method === 'eth_accounts') { + return realSend(payload, function (err, result) { if (err) { return cb(err); } - accounts = accounts.concat(self.addresses); - // accounts = self.addresses.concat(accounts); - cb(null, accounts); - resolve(accounts); + result.result = result.result.concat(self.addresses); + cb(null, result); }); } realSend(payload, cb); @@ -109,36 +73,10 @@ class Provider { if (!self.isDev) { return callback(); } - async.each(self.accounts, (account, eachCb) => { + async.eachLimit(self.accounts, 1, (account, eachCb) => { fundAccount(self.web3, account.address, account.hexBalance, eachCb); }, callback); } - - stop() { - this.engine.stop(); - } - - eth_accounts(payload, cb) { - return cb(null, this.addresses); - } - - sendAsync(payload, callback) { - let method = this.asyncMethods[payload.method]; - if (method) { - return method.call(method, payload, (err, result) => { - if (err) { - return callback(err); - } - let response = {'id': payload.id, 'jsonrpc': '2.0', 'result': result}; - callback(null, response); - }); - } - this.engine.sendAsync.apply(this.engine, arguments); - } - - send() { - return this.engine.send.apply(this.engine, arguments); - } } module.exports = Provider; diff --git a/lib/modules/blockchain_connector/provider.js~HEAD b/lib/modules/blockchain_connector/provider.js~HEAD deleted file mode 100644 index 59b1bdb9..00000000 --- a/lib/modules/blockchain_connector/provider.js~HEAD +++ /dev/null @@ -1,82 +0,0 @@ -const async = require('async'); -const AccountParser = require('../../utils/accountParser'); -const fundAccount = require('./fundAccount'); - -class Provider { - constructor(options) { - this.web3 = options.web3; - this.accountsConfig = options.accountsConfig; - this.blockchainConfig = options.blockchainConfig; - this.type = options.type; - this.web3Endpoint = options.web3Endpoint; - this.logger = options.logger; - this.isDev = options.isDev; - } - - startWeb3Provider(callback) { - const self = this; - - if (this.type === 'rpc') { - self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint); - } else if (this.type === 'ws') { - self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "embark"}}); - } else { - return callback(__("contracts config error: unknown deployment type %s", this.type)); - } - - self.web3.setProvider(self.provider); - - self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger); - self.addresses = []; - - if (!self.accounts.length) { - return callback(); - } - self.accounts.forEach(account => { - self.addresses.push(account.address); - self.web3.eth.accounts.wallet.add(account); - }); - self.web3.eth.defaultAccount = self.addresses[0]; - const realSend = self.provider.send.bind(self.provider); - self.provider.send = function (payload, cb) { - if (payload.method === 'eth_accounts') { - return realSend(payload, function (err, result) { - if (err) { - return cb(err); - } - result.result = result.result.concat(self.addresses); - cb(null, result); - }); - } - realSend(payload, cb); - }; - - callback(); - } - - stop() { - if (this.provider && this.provider.removeAllListeners) { - this.provider.removeAllListeners('connect'); - this.provider.removeAllListeners('error'); - this.provider.removeAllListeners('end'); - this.provider.removeAllListeners('data'); - this.provider.responseCallbacks = {}; - this.provider = null; - } - } - - fundAccounts(callback) { - const self = this; - if (!self.accounts.length) { - return callback(); - } - if (!self.isDev) { - return callback(); - } - async.eachLimit(self.accounts, 1, (account, eachCb) => { - fundAccount(self.web3, account.address, account.hexBalance, eachCb); - }, callback); - } -} - -module.exports = Provider; diff --git a/lib/modules/blockchain_process/blockchain.js b/lib/modules/blockchain_process/blockchain.js index 37835ecf..c50c237b 100644 --- a/lib/modules/blockchain_process/blockchain.js +++ b/lib/modules/blockchain_process/blockchain.js @@ -10,8 +10,6 @@ const DevFunds = require('./dev_funds.js'); const {defaultHost, dockerHostSwap} = require('../../utils/host'); -const {defaultHost, dockerHostSwap} = require('../../utils/host'); - /*eslint complexity: ["error", 36]*/ var Blockchain = function(options) { this.blockchainConfig = options.blockchainConfig; @@ -53,7 +51,6 @@ var Blockchain = function(options) { wsPort: this.blockchainConfig.wsPort || 8546, wsOrigins: this.blockchainConfig.wsOrigins || false, wsApi: (this.blockchainConfig.wsApi || defaultWsApi), - // wsApi: (this.blockchainConfig.wsApi || ['eth', 'web3', 'net', 'shh', 'debug']), vmdebug: this.blockchainConfig.vmdebug || false, targetGasLimit: this.blockchainConfig.targetGasLimit || false, syncMode: this.blockchainConfig.syncMode, diff --git a/lib/modules/ens/contracts/Resolver.sol b/lib/modules/ens/contracts/Resolver.sol index 0b7175b1..0902c4ee 100644 --- a/lib/modules/ens/contracts/Resolver.sol +++ b/lib/modules/ens/contracts/Resolver.sol @@ -182,198 +182,6 @@ contract Resolver { return records[node].content; } - /** - * Returns the address associated with an ENS node. - * @param node The ENS node to query. - * @return The associated address. - */ - function addr(bytes32 node) public view returns (address) { - return records[node].addr; - } -}pragma solidity ^0.4.23; - -import "./ENS.sol"; - -/** - * A simple resolver anyone can use; only allows the owner of a node to set its - * address. - */ -contract Resolver { - event AddrChanged(bytes32 indexed node, address a); - event ContentChanged(bytes32 indexed node, bytes32 hash); - event NameChanged(bytes32 indexed node, string name); - event ABIChanged(bytes32 indexed node, uint256 indexed contentType); - event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); - event TextChanged(bytes32 indexed node, string indexedKey, string key); - - struct PublicKey { - bytes32 x; - bytes32 y; - } - - struct Record { - address addr; - bytes32 content; - string name; - PublicKey pubkey; - mapping(string=>string) text; - mapping(uint256=>bytes) abis; - } - - ENS ens; - - mapping (bytes32 => Record) records; - - modifier only_owner(bytes32 node) { - // FIXME Calling ens.owner makes the transaction fail on privatenet for some reason - // address currentOwner = ens.owner(node); - // require(currentOwner == 0 || currentOwner == msg.sender); - require(true == true); - _; - } - - /** - * Constructor. - * @param ensAddr The ENS registrar contract. - */ - constructor(ENS ensAddr) public { - ens = ensAddr; - } - - /** - * Sets the address associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param addr The address to set. - */ - function setAddr(bytes32 node, address addr) public only_owner(node) { - records[node].addr = addr; - emit AddrChanged(node, addr); - } - - /** - * Sets the content hash associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The node to update. - * @param hash The content hash to set - */ - function setContent(bytes32 node, bytes32 hash) public only_owner(node) { - records[node].content = hash; - emit ContentChanged(node, hash); - } - - /** - * Sets the name associated with an ENS node, for reverse records. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param name The name to set. - */ - function setName(bytes32 node, string name) public only_owner(node) { - records[node].name = name; - emit NameChanged(node, name); - } - - /** - * Sets the ABI associated with an ENS node. - * Nodes may have one ABI of each content type. To remove an ABI, set it to - * the empty string. - * @param node The node to update. - * @param contentType The content type of the ABI - * @param data The ABI data. - */ - function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) { - // Content types must be powers of 2 - require(((contentType - 1) & contentType) == 0); - - records[node].abis[contentType] = data; - emit ABIChanged(node, contentType); - } - - /** - * Sets the SECP256k1 public key associated with an ENS node. - * @param node The ENS node to query - * @param x the X coordinate of the curve point for the public key. - * @param y the Y coordinate of the curve point for the public key. - */ - function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) { - records[node].pubkey = PublicKey(x, y); - emit PubkeyChanged(node, x, y); - } - - /** - * Sets the text data associated with an ENS node and key. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param key The key to set. - * @param value The text data value to set. - */ - function setText(bytes32 node, string key, string value) public only_owner(node) { - records[node].text[key] = value; - emit TextChanged(node, key, key); - } - - /** - * Returns the text data associated with an ENS node and key. - * @param node The ENS node to query. - * @param key The text data key to query. - * @return The associated text data. - */ - function text(bytes32 node, string key) public view returns (string) { - return records[node].text[key]; - } - - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x, y the X and Y coordinates of the curve point for the public key. - */ - function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) { - return (records[node].pubkey.x, records[node].pubkey.y); - } - - /** - * Returns the ABI associated with an ENS node. - * Defined in EIP205. - * @param node The ENS node to query - * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. - * @return contentType The content type of the return value - * @return data The ABI data - */ - function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) { - Record storage record = records[node]; - for (contentType = 1; contentType <= contentTypes; contentType <<= 1) { - if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { - data = record.abis[contentType]; - return; - } - } - contentType = 0; - } - - /** - * Returns the name associated with an ENS node, for reverse records. - * Defined in EIP181. - * @param node The ENS node to query. - * @return The associated name. - */ - function name(bytes32 node) public view returns (string) { - return records[node].name; - } - - /** - * Returns the content hash associated with an ENS node. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The ENS node to query. - * @return The associated content hash. - */ - function content(bytes32 node) public view returns (bytes32) { - return records[node].content; - } - /** * Returns the address associated with an ENS node. * @param node The ENS node to query. diff --git a/lib/modules/ens/embarkjs.js b/lib/modules/ens/embarkjs.js index eed0258e..cac08229 100644 --- a/lib/modules/ens/embarkjs.js +++ b/lib/modules/ens/embarkjs.js @@ -229,8 +229,8 @@ __embarkENS.lookup = function (address, callback) { __embarkENS.registerSubDomain = function (name, address, callback) { callback = callback || function () {}; - if (this.env !== 'development') { - return callback('Sub-domain registration is only available in development mode'); + if (this.env !== 'development' && this.env !== 'privatenet') { + return callback('Sub-domain registration is only available in development or privatenet mode'); } if (!this.registration || !this.registration.rootDomain) { return callback('No rootDomain is declared in config/namesystem.js (register.rootDomain). Unable to register a subdomain until then.'); @@ -241,7 +241,7 @@ __embarkENS.registerSubDomain = function (name, address, callback) { // Register function generated by the index registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount, name, this.registration.rootDomain, - web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, callback); + web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, EmbarkJS.Utils.secureSend, callback); }; __embarkENS.isAvailable = function () { diff --git a/lib/modules/ens/index.js b/lib/modules/ens/index.js index fd30baf2..4d0bf70b 100644 --- a/lib/modules/ens/index.js +++ b/lib/modules/ens/index.js @@ -2,66 +2,153 @@ const fs = require('../../core/fs.js'); const utils = require('../../utils/utils.js'); const namehash = require('eth-ens-namehash'); const async = require('async'); - +const embarkJsUtils = require('embarkjs').Utils; const reverseAddrSuffix = '.addr.reverse'; class ENS { constructor(embark, _options) { + this.env = embark.env; + this.isDev = embark.config.blockchainConfig.isDev; this.logger = embark.logger; this.events = embark.events; this.namesConfig = embark.config.namesystemConfig; this.registration = this.namesConfig.register || {}; this.embark = embark; + if (this.namesConfig === {} || + this.namesConfig.enabled !== true || + this.namesConfig.available_providers.indexOf('ens') < 0) { + return; + } + this.doSetENSProvider = this.namesConfig.provider === 'ens'; + this.addENSToEmbarkJS(); this.configureContracts(); this.registerEvents(); } registerEvents() { - const self = this; - self.embark.registerActionForEvent("contracts:deploy:afterAll", (cb) => { - async.parallel([ - function getENSRegistry(paraCb) { - self.events.request('contracts:contract', "ENSRegistry", (contract) => { - paraCb(null, contract); - }); - }, - function getRegistrar(paraCb) { - self.events.request('contracts:contract', "FIFSRegistrar", (contract) => { - paraCb(null, contract); - }); - }, - function getResolver(paraCb) { - self.events.request('contracts:contract', "Resolver", (contract) => { - paraCb(null, contract); - }); - } - ], (err, results) => { - // result[0] => ENSRegistry; result[1] => FIFSRegistrar; result[2] => FIFSRegistrar - let config = { - env: self.env, - registration: self.registration, - registryAbi: results[0].abiDefinition, - registryAddress: results[0].deployedAddress, - registrarAbi: results[1].abiDefinition, - registrarAddress: results[1].deployedAddress, - resolverAbi: results[2].abiDefinition, - resolverAddress: results[2].deployedAddress - }; - self.addSetProvider(config); + this.embark.registerActionForEvent("contracts:deploy:afterAll", this.setProviderAndRegisterDomains.bind(this)); - if (!self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) { - return cb(); - } - self.registerConfigDomains(config, cb); - }); + this.events.setCommandHandler("storage:ens:associate", this.associateStorageToEns.bind(this)); + } + + setProviderAndRegisterDomains(cb) { + const self = this; + async.parallel([ + function getENSRegistry(paraCb) { + self.events.request('contracts:contract', "ENSRegistry", (contract) => { + paraCb(null, contract); + }); + }, + function getRegistrar(paraCb) { + self.events.request('contracts:contract', "FIFSRegistrar", (contract) => { + paraCb(null, contract); + }); + }, + function getResolver(paraCb) { + self.events.request('contracts:contract', "Resolver", (contract) => { + paraCb(null, contract); + }); + } + ], (err, results) => { + // result[0] => ENSRegistry; result[1] => FIFSRegistrar; result[2] => FIFSRegistrar + let config = { + env: self.env, + registration: self.registration, + registryAbi: results[0].abiDefinition, + registryAddress: results[0].deployedAddress, + registrarAbi: results[1].abiDefinition, + registrarAddress: results[1].deployedAddress, + resolverAbi: results[2].abiDefinition, + resolverAddress: results[2].deployedAddress + }; + + if (self.doSetENSProvider) { + self.addSetProvider(config); + } + + if ((!self.isDev && self.env !== 'privatenet') || !self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) { + return cb(); + } + self.registerConfigDomains(config, cb); }); } + associateStorageToEns(options, cb) { + const self = this; + // Code inspired by https://github.com/monkybrain/ipfs-to-ens + const {name, storageHash} = options; + + if (!utils.isValidEthDomain(name)) { + return cb('Invalid domain name ' + name); + } + + let hashedName = namehash.hash(name); + let contentHash; + try { + contentHash = utils.hashTo32ByteHexString(storageHash); + } catch (e) { + return cb('Invalid IPFS hash'); + } + + // Set content + async.waterfall([ + function getRegistryABI(next) { + self.events.request('contracts:contract', "ENSRegistry", (contract) => { + next(null, contract); + }); + }, + function createRegistryContract(contract, next) { + self.events.request("blockchain:contract:create", + {abi: contract.abiDefinition, address: contract.deployedAddress}, + (resolver) => { + next(null, resolver); + }); + }, + function getResolverForName(registry, next) { + registry.methods.resolver(hashedName).call((err, resolverAddress) => { + if (err) { + return cb(err); + } + if (resolverAddress === '0x0000000000000000000000000000000000000000') { + return cb('Name not yet registered'); + } + next(null, resolverAddress); + }); + }, + function getResolverABI(resolverAddress, next) { + self.events.request('contracts:contract', "Resolver", (contract) => { + next(null, resolverAddress, contract); + }); + }, + function createResolverContract(resolverAddress, contract, next) { + self.events.request("blockchain:contract:create", + {abi: contract.abiDefinition, address: resolverAddress}, + (resolver) => { + next(null, resolver); + }); + }, + function getDefaultAccount(resolver, next) { + self.events.request("blockchain:defaultAccount:get", (defaultAccount) => { + next(null, resolver, defaultAccount); + }); + }, + function setContent(resolver, defaultAccount, next) { + resolver.methods.setContent(hashedName, contentHash).send({from: defaultAccount}).then((transaction) => { + if (transaction.status !== "0x1" && transaction.status !== "0x01" && transaction.status !== true) { + return next('Association failed. Status: ' + transaction.status); + } + next(); + }).catch(next); + } + ], cb); + } + registerConfigDomains(config, cb) { const self = this; const register = require('./register'); + const secureSend = embarkJsUtils.secureSend; self.events.request("blockchain:defaultAccount:get", (defaultAccount) => { async.parallel([ function createRegistryContract(paraCb) { @@ -85,7 +172,7 @@ class ENS { paraCb(null, resolver); }); } - ], function (err, contracts) { + ], function(err, contracts) { if (err) { return cb(err); } @@ -95,7 +182,7 @@ class ENS { const address = self.registration.subdomains[subDomainName]; const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix); register(ens, registrar, resolver, defaultAccount, subDomainName, self.registration.rootDomain, - reverseNode, address, self.logger, eachCb); + reverseNode, address, self.logger, secureSend, eachCb); }, cb); }); @@ -104,20 +191,12 @@ class ENS { addENSToEmbarkJS() { const self = this; - // TODO: make this a shouldAdd condition - if (this.namesConfig === {}) { - return; - } - - if ((this.namesConfig.available_providers.indexOf('ens') < 0) && (this.namesConfig.provider !== 'ens' || this.namesConfig.enabled !== true)) { - return; - } // get namehash, import it into file - self.events.request("version:get:eth-ens-namehash", function (EnsNamehashVersion) { + self.events.request("version:get:eth-ens-namehash", function(EnsNamehashVersion) { let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"]; if (EnsNamehashVersion !== currentEnsNamehashVersion) { - self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function (err, location) { + self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function(err, location) { self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location)); }); } @@ -133,16 +212,24 @@ class ENS { configureContracts() { const config = { "default": { - "gas": "auto" + "gas": "auto", + "contracts": { + "ENS": { + "deploy": false, + "silent": true + } + } }, "development": { "contracts": { "ENSRegistry": { "deploy": true, + "silent": true, "args": [] }, "Resolver": { "deploy": true, + "silent": true, "args": ["$ENSRegistry"] }, "FIFSRegistrar": { @@ -153,7 +240,8 @@ class ENS { "ropsten": { "contracts": { "ENSRegistry": { - "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010" + "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010", + "silent": true }, "Resolver": { "deploy": false @@ -166,7 +254,8 @@ class ENS { "rinkeby": { "contracts": { "ENSRegistry": { - "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" + "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A", + "silent": true }, "Resolver": { "deploy": false @@ -179,7 +268,8 @@ class ENS { "livenet": { "contracts": { "ENSRegistry": { - "address": "0x314159265dd8dbb310642f98f50c066173c1259b" + "address": "0x314159265dd8dbb310642f98f50c066173c1259b", + "silent": true }, "Resolver": { "deploy": false @@ -190,30 +280,34 @@ class ENS { } } }; + config.testnet = config.ropsten; if (this.registration && this.registration.rootDomain) { // Register root domain if it is defined const rootNode = namehash.hash(this.registration.rootDomain); config.development.contracts['FIFSRegistrar'] = { "deploy": true, + "silent": true, "args": ["$ENSRegistry", rootNode], "onDeploy": [ - `ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => { - ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send(); + `ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send({from: web3.eth.defaultAccount}).then(() => { + ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send({from: web3.eth.defaultAccount}); var reverseNode = web3.utils.soliditySha3(web3.eth.defaultAccount.toLowerCase().substr(2) + '${reverseAddrSuffix}'); - ENSRegistry.methods.setResolver(reverseNode, "$Resolver").send(); - Resolver.methods.setAddr('${rootNode}', web3.eth.defaultAccount).send(); - Resolver.methods.setName(reverseNode, '${this.registration.rootDomain}').send(); + ENSRegistry.methods.setResolver(reverseNode, "$Resolver").send({from: web3.eth.defaultAccount}); + Resolver.methods.setAddr('${rootNode}', web3.eth.defaultAccount).send({from: web3.eth.defaultAccount}); + Resolver.methods.setName(reverseNode, '${this.registration.rootDomain}').send({from: web3.eth.defaultAccount}); })` ] }; } - + config.privatenet = config.development; this.embark.registerContractConfiguration(config); - this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/ENSRegistry.sol')); - this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/FIFSRegistrar.sol')); - this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/Resolver.sol')); + if (this.isDev || this.env === 'privatenet') { + this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/ENSRegistry.sol')); + this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/FIFSRegistrar.sol')); + this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/Resolver.sol')); + } } addSetProvider(config) { diff --git a/lib/modules/ens/register.js b/lib/modules/ens/register.js index ba295184..1ebf3478 100644 --- a/lib/modules/ens/register.js +++ b/lib/modules/ens/register.js @@ -1,15 +1,7 @@ /*global web3*/ const namehash = require('eth-ens-namehash'); -<<<<<<< HEAD -<<<<<<< HEAD function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, secureSend, callback) { -======= -function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, callback) { ->>>>>>> if no register config, dont register anything -======= -function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, callback) { ->>>>>>> pre-dploy using the same function as register const subnode = namehash.hash(subdomain); const rootNode = namehash.hash(rootDomain); const node = namehash.hash(`${subdomain}.${rootDomain}`); @@ -18,15 +10,7 @@ function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, const toSend = ens.methods.setSubnodeOwner(rootNode, subnode, defaultAccount); let transaction; -<<<<<<< HEAD secureSend(web3, toSend, {from: defaultAccount}, false) -======= - toSend.estimateGas() - // Register domain - .then(gasEstimated => { - return toSend.send({gas: gasEstimated + 1000, from: defaultAccount}); - }) ->>>>>>> pre-dploy using the same function as register // Set resolver for the node .then(transac => { if (transac.status !== "0x1" && transac.status !== "0x01" && transac.status !== true) { @@ -34,7 +18,6 @@ function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, return callback('Failed to register. Check gas cost.'); } transaction = transac; -<<<<<<< HEAD return secureSend(web3, ens.methods.setResolver(node, resolver.options.address), {from: defaultAccount}, false); }) // Set address for node @@ -48,21 +31,6 @@ function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, // Set name for reverse node .then(_result => { return secureSend(web3, resolver.methods.setName(reverseNode, `${subdomain}.${rootDomain}`), {from: defaultAccount}, false); -======= - return ens.methods.setResolver(node, resolver.options.address).send({from: defaultAccount}); - }) - // Set address for node - .then(_result => { - return resolver.methods.setAddr(node, address).send({from: defaultAccount}); - }) - // Set resolver for the reverse node - .then(_result => { - return ens.methods.setResolver(reverseNode, resolver.options.address).send({from: defaultAccount}); - }) - // Set name for reverse node - .then(_result => { - return resolver.methods.setName(reverseNode, subdomain + '.embark.eth').send({from: defaultAccount}); ->>>>>>> pre-dploy using the same function as register }) .then(_result => { callback(null, transaction); diff --git a/lib/modules/graph/index.js b/lib/modules/graph/index.js index dfb452bd..5ccfe295 100644 --- a/lib/modules/graph/index.js +++ b/lib/modules/graph/index.js @@ -2,7 +2,6 @@ const async = require('async'); const Viz = require('viz.js'); const fs = require('fs'); -// TODO: refactor this class to use the plugin api and not refeneences directly class GraphGenerator { constructor(embark, _options) { const self = this; diff --git a/lib/modules/library_manager/npmTimer.js b/lib/modules/library_manager/npmTimer.js index af37b0ed..95d3a23f 100644 --- a/lib/modules/library_manager/npmTimer.js +++ b/lib/modules/library_manager/npmTimer.js @@ -39,7 +39,6 @@ class NpmTimer{ else{ // otherwise, find our download complete measurement entry = utils.last(items.getEntries().filter(entry => entry.name === this._downloadComplete)); - if(entry){ strDuration = __('Finished downloading and installing {{packageName}} {{version}} in {{duration}}ms', {packageName: this._packageName, version: this._version, duration: entry.duration}); performance.clearMarks(); diff --git a/lib/modules/storage/embarkjs.js b/lib/modules/storage/embarkjs.js deleted file mode 100644 index 20cf842b..00000000 --- a/lib/modules/storage/embarkjs.js +++ /dev/null @@ -1,37 +0,0 @@ -/* global EmbarkJS */ - -import {detectSeries} from 'async'; - -let __embarkStorage = {}; - -__embarkStorage.setProviders = async function (dappConnOptions) { - try { - await detectSeries(dappConnOptions, async (dappConn, callback) => { - if(dappConn === '$BZZ' || dappConn.provider === 'swarm'){ - let options = dappConn; - if(dappConn === '$BZZ') options = {"useOnlyGivenProvider": true}; - try{ - await EmbarkJS.Storage.setProvider('swarm', options); - let isAvailable = await EmbarkJS.Storage.isAvailable(); - callback(null, isAvailable); - }catch(err){ - callback(null, false); // catch errors for when bzz object not initialised but config has requested it to be used - } - } - else if(dappConn.provider === 'ipfs') { - // set the provider then check the connection, if true, use that provider, else, check next provider - try{ - await EmbarkJS.Storage.setProvider('ipfs', dappConn); - let isAvailable = await EmbarkJS.Storage.isAvailable(); - callback(null, isAvailable); - } catch(err) { - callback(null, false); // catch but keep looping by not passing err to callback - } - } - }, function(err, result){ - if(!result) throw new Error('Could not connect to a storage provider using any of the dappConnections in the storage config'); - }); - } catch (err) { - throw new Error('Failed to connect to a storage provider: ' + err.message); - } - }; diff --git a/lib/processes/process_manager.js b/lib/processes/process_manager.js deleted file mode 100644 index 4da9ddea..00000000 --- a/lib/processes/process_manager.js +++ /dev/null @@ -1,39 +0,0 @@ - -class ProcessManager { - constructor(options) { - const self = this; - this.logger = options.logger; - this.events = options.events; - this.plugins = options.plugins; - this.processes = {}; - - self.events.setCommandHandler('processes:register', (name, cb) => { - console.dir("=====> registering " + name); - this.processes[name] = { - state: 'unstarted', - cb: cb - } - }); - - self.events.setCommandHandler('processes:launch', (name, cb) => { - let process = self.processes[name]; - // TODO: should make distinction between starting and running - if (process.state != 'unstarted') { - console.dir("=====> already started " + name); - return cb(); - } - console.dir("=====> launching " + name); - process.state = 'starting'; - //let pry = require('pryjs'); - //eval(pry.it); - process.cb.apply(process.cb, [() => { - process.state = 'running'; - console.dir("=====> launched " + name); - cb(); - }]); - }); - } - -} - -module.exports = ProcessManager; diff --git a/lib/tests/test.js b/lib/tests/test.js index a935a255..64cd218d 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -44,6 +44,7 @@ class Test { } initWeb3Provider(callback) { + const self = this; if (this.provider) { this.provider.stop(); } @@ -80,8 +81,13 @@ class Test { return callback(err); } - this.provider = new Provider(providerOptions); - this.provider.startWeb3Provider(callback); + self.provider = new Provider(providerOptions); + return self.provider.startWeb3Provider((err) => { + if (err) { + return callback(err); + } + callback(); + }); }); } @@ -309,6 +315,7 @@ class Test { }, (err) => { next(err, accounts); }); + }); } ], function (err, accounts) { diff --git a/lib/utils/utils.js b/lib/utils/utils.js index 734a774b..92facc19 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -447,25 +447,6 @@ function interceptLogs(consoleContext, logger) { }; } -function compact(array) { - return array.filter(n => n); -} - -function groupBy(array, key) { - return array.reduce(function(rv, x) { - (rv[x[key]] = rv[x[key]] || []).push(x); - return rv; - }, {}); -} - -function sample(array) { - return array[Math.floor(Math.random() * array.length)]; -} - -function last(array) { - return array[array.length - 1]; -} - module.exports = { joinPath, dirname, diff --git a/package.json b/package.json index ea1151ee..ca8d4e37 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,7 @@ "decompress": "^4.2.0", "deep-equal": "^1.0.1", "ejs": "^2.5.8", -<<<<<<< HEAD "embarkjs": "^0.3.4", -======= - "embarkjs": "^0.3.0", ->>>>>>> up embarkJS version "eth-ens-namehash": "^2.0.8", "eth-lib": "^0.2.8", "ethereumjs-wallet": "0.6.0", diff --git a/test_apps/test_app/config/blockchain.json b/test_apps/test_app/config/blockchain.json index a3247a56..fd4f0a51 100644 --- a/test_apps/test_app/config/blockchain.json +++ b/test_apps/test_app/config/blockchain.json @@ -1,4 +1,4 @@ - +{ "default": { "enabled": true, "rpcHost": "localhost", @@ -13,7 +13,6 @@ "networkType": "custom", "networkId": "1337", "isDev": true, - "genesisBlock": "config/development/genesis.json", "datadir": ".embark/development/datadir", "mineWhenNeeded": true, "nodiscover": true, diff --git a/test_apps/test_app/embark.json b/test_apps/test_app/embark.json index b32984a6..322e0b5f 100644 --- a/test_apps/test_app/embark.json +++ b/test_apps/test_app/embark.json @@ -16,7 +16,7 @@ "config": "config/", "versions": { "solc": "0.4.24", - "web3": "1.0.0-beta.34", + "web3": "1.0.0-beta", "ipfs-api": "17.2.7" }, "plugins": { diff --git a/test_apps/test_app/test/ens_spec.js b/test_apps/test_app/test/ens_spec.js index 200f2634..7c564734 100644 --- a/test_apps/test_app/test/ens_spec.js +++ b/test_apps/test_app/test/ens_spec.js @@ -17,22 +17,28 @@ config({ "args": ["$ENSRegistry", rootNode], "onDeploy": [ `ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => { - ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send(); - Resolver.methods.setAddr('${rootNode}', '${address}').send(); - })` + ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send(); + Resolver.methods.setAddr('${rootNode}', '${address}').send().then(() => { + global.ensTestReady = true; + }); + });` ] } } }); contract("ENS", function () { - this.timeout(0); + this.timeout(1000); before(function (done) { // Wait for onDeploy to finish - setTimeout(function () { + const wait = setInterval(() => { + if (!global.ensTestReady) { + return; + } + clearInterval(wait); done(); - }, 500); + }, 50); }); it("should have registered embark.eth", async function () {