<commit_before>/* globals Promise:true */

var _ = require('lodash')
var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits
var bitcore = require('bitcore')
var Promise = require('bluebird')

var config = require('../../../lib/config')
var logger = require('../../../lib/logger').logger
var util = require('../../../lib/util')
var SQL = require('./sql')

var Address = bitcore.Address
var Hash = bitcore.crypto.Hash

/**
 * @event Sync#latest
 * @param {{hash: string, height: number}} latest
 */

/**
 * @class Sync
 * @extends events.EventEmitter
 * @param {Storage} storage
 * @param {Network} network
 * @param {Slaves} slaves
 */
function Sync (storage, network, slaves) {
  EventEmitter.call(this)

  this._storage = storage
  this._network = network
  this._slaves = slaves

  var networkName = config.get('chromanode.network')
  this._bitcoinNetwork = bitcore.Networks.get(networkName)

  this._latest = null
  this._blockchainLatest = null
}

inherits(Sync, EventEmitter)

/**
 * @param {Buffer} buf
 * @param {string} type
 * @return {string}
 */
Sync.prototype._createAddress = function (buf, type) {
  var address = new Address(buf, this._bitcoinNetwork, type)
  return address.toString()
}

/**
 * @param {bitcore.Script} script
 * @return {string[]}
 */
Sync.prototype._getAddresses = function (script) {
  var self = this

  if (script.isPublicKeyHashOut()) {
    return [
      self._createAddress(script.chunks[2].buf, Address.PayToPublicKeyHash)
    ]
  }

  if (script.isScriptHashOut()) {
    return [
      self._createAddress(script.chunks[1].buf, Address.PayToScriptHash)
    ]
  }

  if (script.isMultisigOut()) {
    return script.chunks.slice(1, -2).map(function (chunk) {
      var hash = Hash.sha256ripemd160(chunk.buf)
      return self._createAddress(hash, Address.PayToPublicKeyHash)
    })
  }

  if (script.isPublicKeyOut()) {
    var hash = Hash.sha256ripemd160(script.chunks[0].buf)
    return [
      self._createAddress(hash, Address.PayToPublicKeyHash)
    ]
  }

  return []
}

/**
 * @param {bitcore.Transaction.Output} output
 * @param {string} txid
 * @param {number} index
 * @return {string[]}
 */
Sync.prototype._safeGetAddresses = function (output, txid, index) {
  try {
    return this._getAddresses(output.script)
  } catch (err) {
    logger.error('On get addresses for output %s:%s %s',
                 txid, index, err.stack)
    return []
  }
}

/**
 * @param {number} to
 * @param {pg.Client} client
 * @return {Promise}
 */
Sync.prototype._reorgTo = function (to, client) {
}

/**
 * @return {Promise<boolean>}
 */
Sync.prototype._updateChain = function () {
  var self = this
  if (self._latest.hash === self._blockchainLatest.hash) {
    return Promise.resolve(false)
  }

  var stopwatch
  var latest = _.clone(self._latest)
  return self._storage.executeTransaction(function (client) {
    return new Promise(function (resolve, reject) {
      function tryGetBlock () {
        return self._getBlock(latest.height + 1)
          .then(function (block) {
            if (latest.height < self._blockchainLatest.height &&
                latest.hash === util.encode(block.header.prevHash)) {
              return resolve(block)
            }

            // reorg found
            if (self._blockCache !== undefined) {
              self._blockCache.reset()
            }

            var to = Math.min(latest.height - 1,
                              self._blockchainLatest.height - 1)
            var opts = {client: client, concurrency: 1}

            stopwatch = util.stopwatch.start()
            return self._storage.executeQueries([
              [SQL.delete.blocks.fromHeight, [to]],
              [SQL.delete.transactions.fromHeight, [to]],
              [SQL.delete.history.fromHeight, [to]],
              [SQL.update.history.deleteInputsFromHeight, [to]]
            ], opts)
            .then(function () {
              logger.warn('Reorg finished (back to %d), elapsed time: %s',
                             to, stopwatch.formattedValue())
              return self._getMyLatest({client: client})
            })
            .then(function (newLatest) {
              latest = newLatest
            })
            .then(tryGetBlock, reject)
          })
      }

      tryGetBlock()
    })
    .then(function (block) {
      stopwatch = util.stopwatch.start()
      return self._importBlock(block, latest.height + 1, client)
    })
    .then(function () {
      stopwatch = stopwatch.value()
      return self._getMyLatest({client: client})
    })
  })
  .then(function (newLatest) {
    // new latest
    self._latest = newLatest

    // verbose logging
    logger.verbose('Import block #%d, elapsed time: %s (hash: %s)',
                   self._latest.height,
                   util.stopwatch.format(stopwatch),
                   self._latest.hash)

    return true
  })
}

/**
 * @param {Objects} [opts]<commit_msg>fix _updateChain<commit_after>/* globals Promise:true */

var _ = require('lodash')
var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits
var bitcore = require('bitcore')
var Promise = require('bluebird')

var config = require('../../../lib/config')
var logger = require('../../../lib/logger').logger
var util = require('../../../lib/util')
var SQL = require('./sql')

var Address = bitcore.Address
var Hash = bitcore.crypto.Hash

/**
 * @event Sync#latest
 * @param {{hash: string, height: number}} latest
 */

/**
 * @class Sync
 * @extends events.EventEmitter
 * @param {Storage} storage
 * @param {Network} network
 * @param {Slaves} slaves
 */
function Sync (storage, network, slaves) {
  EventEmitter.call(this)

  this._storage = storage
  this._network = network
  this._slaves = slaves

  var networkName = config.get('chromanode.network')
  this._bitcoinNetwork = bitcore.Networks.get(networkName)

  this._latest = null
  this._blockchainLatest = null
}

inherits(Sync, EventEmitter)

/**
 * @param {Buffer} buf
 * @param {string} type
 * @return {string}
 */
Sync.prototype._createAddress = function (buf, type) {
  var address = new Address(buf, this._bitcoinNetwork, type)
  return address.toString()
}

/**
 * @param {bitcore.Script} script
 * @return {string[]}
 */
Sync.prototype._getAddresses = function (script) {
  var self = this

  if (script.isPublicKeyHashOut()) {
    return [
      self._createAddress(script.chunks[2].buf, Address.PayToPublicKeyHash)
    ]
  }

  if (script.isScriptHashOut()) {
    return [
      self._createAddress(script.chunks[1].buf, Address.PayToScriptHash)
    ]
  }

  if (script.isMultisigOut()) {
    return script.chunks.slice(1, -2).map(function (chunk) {
      var hash = Hash.sha256ripemd160(chunk.buf)
      return self._createAddress(hash, Address.PayToPublicKeyHash)
    })
  }

  if (script.isPublicKeyOut()) {
    var hash = Hash.sha256ripemd160(script.chunks[0].buf)
    return [
      self._createAddress(hash, Address.PayToPublicKeyHash)
    ]
  }

  return []
}

/**
 * @param {bitcore.Transaction.Output} output
 * @param {string} txid
 * @param {number} index
 * @return {string[]}
 */
Sync.prototype._safeGetAddresses = function (output, txid, index) {
  try {
    return this._getAddresses(output.script)
  } catch (err) {
    logger.error('On get addresses for output %s:%s %s',
                 txid, index, err.stack)
    return []
  }
}

/**
 * @param {number} to
 * @param {pg.Client} client
 * @return {Promise}
 */
Sync.prototype._reorgTo = function (to, client) {
}

/**
 * @return {Promise<boolean>}
 */
Sync.prototype._updateChain = function () {
  var self = this
  if (self._latest.hash === self._blockchainLatest.hash) {
    return Promise.resolve(false)
  }

  var stopwatch
  var latest = _.clone(self._latest)
  return self._storage.executeTransaction(function (client) {
    return new Promise(function (resolve, reject) {
      function tryGetBlock () {
        return self._getBlock(latest.height + 1)
          .then(function (block) {
            if (latest.height < self._blockchainLatest.height &&
                latest.hash === util.encode(block.header.prevHash)) {
              return resolve(block)
            }

            // reorg found
            if (self._blockCache !== undefined) {
              self._blockCache.reset()
            }

            var to = Math.min(latest.height - 1,
                              self._blockchainLatest.height - 1)
            var opts = {client: client, concurrency: 1}

            stopwatch = util.stopwatch.start()
            return self._storage.executeQueries([
              [SQL.delete.blocks.fromHeight, [to]],
              [SQL.delete.transactions.fromHeight, [to]],
              [SQL.delete.history.fromHeight, [to]],
              [SQL.update.history.deleteInputsFromHeight, [to]]
            ], opts)
            .then(function () {
              logger.warn('Reorg finished (back to %d), elapsed time: %s',
                             to, stopwatch.formattedValue())
              return self._getMyLatest({client: client})
            })
            .then(function (newLatest) {
              latest = newLatest
            })
            .then(tryGetBlock)
          })
          .catch(reject)
      }

      tryGetBlock()
    })
    .then(function (block) {
      stopwatch = util.stopwatch.start()
      return self._importBlock(block, latest.height + 1, client)
    })
    .then(function () {
      stopwatch = stopwatch.value()
      return self._getMyLatest({client: client})
    })
  })
  .then(function (newLatest) {
    // new latest
    self._latest = newLatest

    // verbose logging
    logger.verbose('Import block #%d, elapsed time: %s (hash: %s)',
                   self._latest.height,
                   util.stopwatch.format(stopwatch),
                   self._latest.hash)

    return true
  })
}

/**
 * @param {Objects} [opts]
{'fraction_non_alphanumeric': 0.14048582995951417, 'fraction_numerical': 0.004453441295546558, 'mean_word_length': 2.4682344682344683, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '4856428', 'n_tokens_mistral': 3036, 'n_tokens_neox': 2973, 'n_words': 630}