<commit_before>const async = require('async');
const child_process = require('child_process');

const fs = require('../../core/fs.js');
const constants = require('../../constants.json');
const utils = require('../../utils/utils.js');

const GethCommands = require('./geth_commands.js');
const DevFunds = require('./dev_funds.js');

const {defaultHost, dockerHostSwap} = require('../../utils/host');

/*eslint complexity: ["error", 36]*/
var Blockchain = function(options) {
  this.blockchainConfig = options.blockchainConfig;
  this.env = options.env || 'development';
  this.client = options.client;
  this.isDev = options.isDev;
  this.onReadyCallback = options.onReadyCallback || (() => {});
  this.onExitCallback = options.onExitCallback;

  if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
    console.log("===> " + __("warning: running default config on a non-development environment"));
  }

  let defaultWsApi = ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub'];
  if (this.isDev) {
    defaultWsApi.push('personal');
  }

  this.config = {
    geth_bin: this.blockchainConfig.geth_bin || 'geth',
    networkType: this.blockchainConfig.networkType || 'custom',
    genesisBlock: this.blockchainConfig.genesisBlock || false,
    datadir: this.blockchainConfig.datadir || false,
    mineWhenNeeded: this.blockchainConfig.mineWhenNeeded || false,
    rpcHost: dockerHostSwap(this.blockchainConfig.rpcHost) || defaultHost,
    rpcPort: this.blockchainConfig.rpcPort || 8545,
    rpcCorsDomain: this.blockchainConfig.rpcCorsDomain || false,
    networkId: this.blockchainConfig.networkId || 1337,
    port: this.blockchainConfig.port || 30303,
    nodiscover: this.blockchainConfig.nodiscover || false,
    mine: this.blockchainConfig.mine || false,
    account: this.blockchainConfig.account || {},
    whisper: (this.blockchainConfig.whisper === undefined) || this.blockchainConfig.whisper,
    maxpeers: ((this.blockchainConfig.maxpeers === 0) ? 0 : (this.blockchainConfig.maxpeers || 25)),
    bootnodes: this.blockchainConfig.bootnodes || "",
    rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net', 'debug']),
    wsRPC: (this.blockchainConfig.wsRPC === undefined) || this.blockchainConfig.wsRPC,
    wsHost: dockerHostSwap(this.blockchainConfig.wsHost) || defaultHost,
    wsPort: this.blockchainConfig.wsPort || 8546,
    wsOrigins: this.blockchainConfig.wsOrigins || false,
    wsApi: (this.blockchainConfig.wsApi || defaultWsApi),
    vmdebug: this.blockchainConfig.vmdebug || false,
    targetGasLimit: this.blockchainConfig.targetGasLimit || false,
    syncMode: this.blockchainConfig.syncMode,
    syncmode: this.blockchainConfig.syncmode,
    verbosity: this.blockchainConfig.verbosity
  };

  if (this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') {
    this.config.account = {};
    this.config.account.password = fs.embarkPath("templates/boilerplate/config/development/password");
    this.config.genesisBlock = fs.embarkPath("templates/boilerplate/config/development/genesis.json");
    this.config.datadir = fs.dappPath(".embark/development/datadir");
  }

  const spaceMessage = 'The path for %s in blockchain config contains spaces, please remove them';
  if (this.config.datadir && this.config.datadir.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'datadir'));
    process.exit();
  }
  if (this.config.account.password && this.config.account.password.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'account.password'));
    process.exit();
  }
  if (this.config.genesisBlock && this.config.genesisBlock.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'genesisBlock'));
    process.exit();
  }
  this.initProxy();
  this.client = new options.client({config: this.config, env: this.env, isDev: this.isDev});
};

Blockchain.prototype.initProxy = function() {
  this.config.proxy = true;
  if (this.blockchainConfig.proxy === false) {
    this.config.proxy = false;
    return;
  }

  this.config.rpcPort += constants.blockchain.servicePortOnProxy;
  this.config.wsPort += constants.blockchain.servicePortOnProxy;
};

Blockchain.prototype.setupProxy = async function() {
  const proxy = require('./proxy');
  const Ipc = require('../../core/ipc');

  let ipcObject = new Ipc({ipcRole: 'client'});
  const [rpcProxy, wsProxy] = await Promise.all([
    proxy.serve(ipcObject, this.config.rpcHost, this.config.rpcPort, false),
    proxy.serve(ipcObject, this.config.wsHost, this.config.wsPort, true, this.config.wsOrigins)
  ]);
  this.rpcProxy = rpcProxy;
  this.wsProxy = wsProxy;
};

Blockchain.prototype.shutdownProxy = function() {
  if (!this.config.proxy) {
    return;
  }

  this.rpcProxy.close();
  this.wsProxy.close();
};

Blockchain.prototype.runCommand = function(cmd, options, callback) {
  console.log(__("running: %s", cmd.underline).green);
  if (this.blockchainConfig.silent) {
    options.silent = true;
  }
  return child_process.exec(cmd, options, callback);
};

Blockchain.prototype.run = function() {
  var self = this;
  console.log("===============================================================================".magenta);
  console.log("===============================================================================".magenta);
  console.log(__("Embark Blockchain Using: %s", this.client.name.underline).magenta);
  console.log("===============================================================================".magenta);
  console.log("===============================================================================".magenta);
  this.checkPathLength();
  let address = '';
  async.waterfall([
    function checkInstallation(next) {
      self.isClientInstalled((err) => {
        if (err) {
          console.log(__("could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?", {geth_bin: this.config.geth_bin, client_name: this.client.name}).green);
          return next(err);
        }
        next();
      });
    },
    function init(next) {
      if (!self.isDev) {
        return self.initChainAndGetAddress((err, addr) => {
          address = addr;
          next(err);
        });
      }
      next();
    },
    function getMainCommand(next) {
      self.client.mainCommand(address, function(cmd, args) {
        if (self.config.proxy) {
          self.setupProxy();
        }
        next(null, cmd, args);
      }, true);
    }
  ], function (err, cmd, args) {
    if (err) {
      console.error(err.message);
      return;
    }
    args = utils.compact(args);

    let full_cmd = cmd + " " + args.join(' ');
    console.log(__("running: %s", full_cmd.underline).green);
    self.child = child_process.spawn(cmd, args, {cwd: process.cwd()});
    self.child.on('error', (err) => {
      err = err.toString();
      console.error('Blockchain error: ', err);
      if (self.env === 'development' && err.indexOf('Failed to unlock') > 0) {
        console.error('\n' + __('Development blockchain has changed to use the --dev option.').yellow);
        console.error(__('You can reset your workspace to fix the problem with').yellow + ' embark reset'.cyan);
        console.error(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
      }
    });
    self.child.stdout.on('data', (data) => {
      console.error(`Geth error: ${data}`);
    });
    // Geth logs appear in stderr somehow
    self.child.stderr.on('data', (data) => {
      data = data.toString();
      if (!self.readyCalled && data.indexOf('WebSocket endpoint opened') > -1) {
        if (self.isDev) {
          self.createFundAndUnlockAccounts((err) => {
            // TODO: this is never called!
            if(err) console.error('Error creating, unlocking, and funding accounts', err);
          });
        }
        self.readyCalled = true;
        self.readyCallback();
      }
      console.log('Geth: ' + data);
    });<commit_msg>await proxy just before createFundAndUnlockAccounts<commit_after>const async = require('async');
const child_process = require('child_process');

const fs = require('../../core/fs.js');
const constants = require('../../constants.json');
const utils = require('../../utils/utils.js');

const GethCommands = require('./geth_commands.js');
const DevFunds = require('./dev_funds.js');

const {defaultHost, dockerHostSwap} = require('../../utils/host');

/*eslint complexity: ["error", 36]*/
var Blockchain = function(options) {
  this.blockchainConfig = options.blockchainConfig;
  this.env = options.env || 'development';
  this.client = options.client;
  this.isDev = options.isDev;
  this.onReadyCallback = options.onReadyCallback || (() => {});
  this.onExitCallback = options.onExitCallback;

  if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
    console.log("===> " + __("warning: running default config on a non-development environment"));
  }

  let defaultWsApi = ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub'];
  if (this.isDev) {
    defaultWsApi.push('personal');
  }

  this.config = {
    geth_bin: this.blockchainConfig.geth_bin || 'geth',
    networkType: this.blockchainConfig.networkType || 'custom',
    genesisBlock: this.blockchainConfig.genesisBlock || false,
    datadir: this.blockchainConfig.datadir || false,
    mineWhenNeeded: this.blockchainConfig.mineWhenNeeded || false,
    rpcHost: dockerHostSwap(this.blockchainConfig.rpcHost) || defaultHost,
    rpcPort: this.blockchainConfig.rpcPort || 8545,
    rpcCorsDomain: this.blockchainConfig.rpcCorsDomain || false,
    networkId: this.blockchainConfig.networkId || 1337,
    port: this.blockchainConfig.port || 30303,
    nodiscover: this.blockchainConfig.nodiscover || false,
    mine: this.blockchainConfig.mine || false,
    account: this.blockchainConfig.account || {},
    whisper: (this.blockchainConfig.whisper === undefined) || this.blockchainConfig.whisper,
    maxpeers: ((this.blockchainConfig.maxpeers === 0) ? 0 : (this.blockchainConfig.maxpeers || 25)),
    bootnodes: this.blockchainConfig.bootnodes || "",
    rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net', 'debug']),
    wsRPC: (this.blockchainConfig.wsRPC === undefined) || this.blockchainConfig.wsRPC,
    wsHost: dockerHostSwap(this.blockchainConfig.wsHost) || defaultHost,
    wsPort: this.blockchainConfig.wsPort || 8546,
    wsOrigins: this.blockchainConfig.wsOrigins || false,
    wsApi: (this.blockchainConfig.wsApi || defaultWsApi),
    vmdebug: this.blockchainConfig.vmdebug || false,
    targetGasLimit: this.blockchainConfig.targetGasLimit || false,
    syncMode: this.blockchainConfig.syncMode,
    syncmode: this.blockchainConfig.syncmode,
    verbosity: this.blockchainConfig.verbosity
  };

  if (this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') {
    this.config.account = {};
    this.config.account.password = fs.embarkPath("templates/boilerplate/config/development/password");
    this.config.genesisBlock = fs.embarkPath("templates/boilerplate/config/development/genesis.json");
    this.config.datadir = fs.dappPath(".embark/development/datadir");
  }

  const spaceMessage = 'The path for %s in blockchain config contains spaces, please remove them';
  if (this.config.datadir && this.config.datadir.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'datadir'));
    process.exit();
  }
  if (this.config.account.password && this.config.account.password.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'account.password'));
    process.exit();
  }
  if (this.config.genesisBlock && this.config.genesisBlock.indexOf(' ') > 0) {
    console.error(__(spaceMessage, 'genesisBlock'));
    process.exit();
  }
  this.initProxy();
  this.client = new options.client({config: this.config, env: this.env, isDev: this.isDev});
};

Blockchain.prototype.initProxy = function() {
  this.config.proxy = true;
  if (this.blockchainConfig.proxy === false) {
    this.config.proxy = false;
    return;
  }

  this.config.rpcPort += constants.blockchain.servicePortOnProxy;
  this.config.wsPort += constants.blockchain.servicePortOnProxy;
};

Blockchain.prototype.setupProxy = async function() {
  const proxy = require('./proxy');
  const Ipc = require('../../core/ipc');

  let ipcObject = new Ipc({ipcRole: 'client'});
  const [rpcProxy, wsProxy] = await Promise.all([
    proxy.serve(ipcObject, this.config.rpcHost, this.config.rpcPort, false),
    proxy.serve(ipcObject, this.config.wsHost, this.config.wsPort, true, this.config.wsOrigins)
  ]);
  this.rpcProxy = rpcProxy;
  this.wsProxy = wsProxy;
};

Blockchain.prototype.shutdownProxy = function() {
  if (!this.config.proxy) {
    return;
  }

  this.rpcProxy.close();
  this.wsProxy.close();
};

Blockchain.prototype.runCommand = function(cmd, options, callback) {
  console.log(__("running: %s", cmd.underline).green);
  if (this.blockchainConfig.silent) {
    options.silent = true;
  }
  return child_process.exec(cmd, options, callback);
};

Blockchain.prototype.run = function() {
  var self = this;
  console.log("===============================================================================".magenta);
  console.log("===============================================================================".magenta);
  console.log(__("Embark Blockchain Using: %s", this.client.name.underline).magenta);
  console.log("===============================================================================".magenta);
  console.log("===============================================================================".magenta);
  this.checkPathLength();
  let address = '';
  async.waterfall([
    function checkInstallation(next) {
      self.isClientInstalled((err) => {
        if (err) {
          console.log(__("could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?", {geth_bin: this.config.geth_bin, client_name: this.client.name}).green);
          return next(err);
        }
        next();
      });
    },
    function init(next) {
      if (!self.isDev) {
        return self.initChainAndGetAddress((err, addr) => {
          address = addr;
          next(err);
        });
      }
      next();
    },
    function getMainCommand(next) {
      self.client.mainCommand(address, function(cmd, args) {
        next(null, cmd, args);
      }, true);
    }
  ], async function (err, cmd, args) {
    if (err) {
      console.error(err.message);
      return;
    }
    args = utils.compact(args);

    let full_cmd = cmd + " " + args.join(' ');
    console.log(__("running: %s", full_cmd.underline).green);
    self.child = child_process.spawn(cmd, args, {cwd: process.cwd()});
    self.child.on('error', (err) => {
      err = err.toString();
      console.error('Blockchain error: ', err);
      if (self.env === 'development' && err.indexOf('Failed to unlock') > 0) {
        console.error('\n' + __('Development blockchain has changed to use the --dev option.').yellow);
        console.error(__('You can reset your workspace to fix the problem with').yellow + ' embark reset'.cyan);
        console.error(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
      }
    });
    self.child.stdout.on('data', (data) => {
      console.error(`Geth error: ${data}`);
    });
    // Geth logs appear in stderr somehow
    self.child.stderr.on('data', async (data) => {
      data = data.toString();
      if (!self.readyCalled && data.indexOf('WebSocket endpoint opened') > -1) {
        if (self.isDev) {
          if (self.config.proxy) {
            await self.setupProxy();
          }
          self.createFundAndUnlockAccounts((err) => {
            // TODO: this is never called!
            if(err) console.error('Error creating, unlocking, and funding accounts', err);
          });
        }
        self.readyCalled = true;
        self.readyCallback();
      }
      console.log('Geth: ' + data);
    });
{'fraction_non_alphanumeric': 0.19488459139114162, 'fraction_numerical': 0.0037429819089207735, 'mean_word_length': 3.7739726027397262, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7579533', 'n_tokens_mistral': 4990, 'n_tokens_neox': 4814, 'n_words': 915}