<commit_before>'use strict'
var async = require('async')
var EventManager = require('ethereum-remix').lib.EventManager
var remix = require('ethereum-remix')
var codeUtil = remix.util.code
var Web3VMProvider = remix.web3.web3VMProvider

/**
  * poll web3 each 2s if web3
  * listen on transaction executed event if VM
  * attention: blocks returned by the event `newBlock` have slightly different json properties whether web3 or the VM is used
  * trigger 'newBlock'
  *
  */
class TxListener {
  constructor (opt) {
    this.event = new EventManager()
    this._appAPI = opt.appAPI
    this._web3VMProvider = new Web3VMProvider() // TODO this should maybe be put in app.js
    this._web3VMProvider.setVM(opt.appAPI.vm())
    this._resolvedTransactions = {}
    this._resolvedContracts = {}
    this.init()
    opt.appEvent.executionContext.register('contextChanged', (context) => {
      if (this.loopId) {
        this.startListening(context)
      }
    })
    opt.appEvent.udapp.register('transactionExecuted', (to, data, lookupOnly, txResult) => {
      if (this.loopId && this._appAPI.isVM()) {
        this._web3VMProvider.getTransaction(txResult.transactionHash, (error, tx) => {
          if (error) return console.log(error)
          this._newBlock({
            type: 'VM',
            number: -1,
            transactions: [tx]
          })
        })
      }
    })
  }

  /**
    * reset recorded transactions
    */
  init () {
    this.blocks = []
    this.lastBlock = null
  }

  /**
    * start listening for incoming transactions
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  startListening () {
    this.stopListening()
    this.init()
    if (this._appAPI.context() === 'vm') {
      this.loopId = 'vm-listener'
    } else {
      this.loopId = setInterval(() => {
        this._appAPI.web3().eth.getBlockNumber((error, blockNumber) => {
          if (error) return console.log(error)
          if (!this.lastBlock || blockNumber > this.lastBlock) {
            this.lastBlock = blockNumber
            this._appAPI.web3().eth.getBlock(this.lastBlock, true, (error, result) => {
              if (!error) {
                this._newBlock(Object.assign({type: 'web3'}, result))
              }
            })
          }
        })
      }, 2)
    }
  }

  currentWeb3 () { // TODO this should maybe be put in app.js
    return this._appAPI.isVM() ? this._web3VMProvider : this._appAPI.web3()
  }

  /**
    * stop listening for incoming transactions. do not reset the recorded pool.
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  stopListening () {
    if (this.loopId) {
      clearInterval(this.loopId)
    }
    this.loopId = null
  }

  /**
    * try to resolve the contract name from the given @arg address
    *
    * @param {String} address - contract address to resolve
    * @return {String} - contract name
    */
  resolvedContract (address) {
    return this._resolvedContracts[address]
  }

  /**
    * try to resolve the transaction from the given @arg txHash
    *
    * @param {String} txHash - contract address to resolve
    * @return {String} - contract name
    */
  resolvedTransaction (txHash) {
    return this._resolvedTransactions[txHash]
  }

  _newBlock (block) {
    this.blocks.push(block)
    this._resolve(block, () => {
      this.event.trigger('newBlock', [block])
    })
  }

  _resolve (block, callback) {
    async.each(block.transactions, (tx, cb) => {
      this._resolveTx(tx, cb)
    }, () => {
      callback()
    })
  }

  _resolveTx (tx, cb) {
    var contracts = this._appAPI.contracts()
    if (!contracts) return cb()
    var contractName
    if (!tx.to) {
      // contract creation / resolve using the creation bytes code
      // if web3: we have to call getTransactionReceipt to get the created address
      // if VM: created address already included
      var code = tx.input
      contractName = this._tryResolveContract(code, contracts, 'bytecode')
      if (contractName) {
        this._resolveCreationAddress(tx, (error, address) => {
          if (error) return cb(error)
          this._resolvedContracts[address] = contractName
          this._resolveFunction(contractName, contracts, tx, true)
          if (this._resolvedTransactions[tx.hash]) {
            this._resolvedTransactions[tx.hash].contractAddress = address
          }
          return cb()
        })
        return
      }
      return cb()
    } else {
      // first check known contract, resolve against the `runtimeBytecode` if not known
      contractName = this._resolvedContracts[tx.to]
      if (!contractName) {
        this.currentWeb3().eth.getCode(tx.to, (error, code) => {
          if (error) return cb(error)
          if (code) {
            var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode')
            if (contractName) {
              this._resolvedContracts[tx.to] = contractName
              this._resolveFunction(contractName, contracts, tx, false)
              return cb()
            }
            return cb()
          }
          return cb()
        })
        return
      }
      if (contractName) {
        this._resolveFunction(contractName, contracts, tx, false)
        return cb()
      }
      return cb()
    }
  }

  _resolveCreationAddress (tx, cb) {
    this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
      if (!error) {
        cb(null, receipt.contractAddress)
      } else {
        cb(error)
      }
    })
  }

  _resolveFunction (contractName, compiledContracts, tx, isCtor) {
    if (!isCtor) {
      for (var fn in compiledContracts[contractName].functionHashes) {
        if (compiledContracts[contractName].functionHashes[fn] === tx.input.replace('0x', '').substring(0, 8)) {
          this._resolvedTransactions[tx.hash] = {
            to: tx.to,
            fn: fn,
            params: null
          }
        }
      // fallback function
      this._resolvedTransactions[tx.hash] = {
        to: tx.to,
        fn: '(fallback)',
        params: null
      }
    } else {
      this._resolvedTransactions[tx.hash] = {
        to: null,
        fn: '(constructor)',
        params: null
      }
    }
  }

  _tryResolveContract (codeToResolve, compiledContracts, type) {
    for (var k in compiledContracts) {
      if (codeUtil.compareByteCode(codeToResolve, '0x' + compiledContracts[k][type])) {
        return k
      }
    }
    return null
  }
}

module.exports = TxListener<commit_msg>decodeParam in tx listener<commit_after>'use strict'
var async = require('async')
var ethJSABI = require('ethereumjs-abi')
var ethJSUtil = require('ethereumjs-util')
var EventManager = require('ethereum-remix').lib.EventManager
var remix = require('ethereum-remix')
var codeUtil = remix.util.code
var Web3VMProvider = remix.web3.web3VMProvider

/**
  * poll web3 each 2s if web3
  * listen on transaction executed event if VM
  * attention: blocks returned by the event `newBlock` have slightly different json properties whether web3 or the VM is used
  * trigger 'newBlock'
  *
  */
class TxListener {
  constructor (opt) {
    this.event = new EventManager()
    this._appAPI = opt.appAPI
    this._web3VMProvider = new Web3VMProvider() // TODO this should maybe be put in app.js
    this._web3VMProvider.setVM(opt.appAPI.vm())
    this._resolvedTransactions = {}
    this._resolvedContracts = {}
    this.init()
    opt.appEvent.executionContext.register('contextChanged', (context) => {
      if (this.loopId) {
        this.startListening(context)
      }
    })
    opt.appEvent.udapp.register('transactionExecuted', (to, data, lookupOnly, txResult) => {
      if (this.loopId && this._appAPI.isVM()) {
        this._web3VMProvider.getTransaction(txResult.transactionHash, (error, tx) => {
          if (error) return console.log(error)
          this._newBlock({
            type: 'VM',
            number: -1,
            transactions: [tx]
          })
        })
      }
    })
  }

  /**
    * reset recorded transactions
    */
  init () {
    this.blocks = []
    this.lastBlock = null
  }

  /**
    * start listening for incoming transactions
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  startListening () {
    this.stopListening()
    this.init()
    if (this._appAPI.context() === 'vm') {
      this.loopId = 'vm-listener'
    } else {
      this.loopId = setInterval(() => {
        this._appAPI.web3().eth.getBlockNumber((error, blockNumber) => {
          if (error) return console.log(error)
          if (!this.lastBlock || blockNumber > this.lastBlock) {
            this.lastBlock = blockNumber
            this._appAPI.web3().eth.getBlock(this.lastBlock, true, (error, result) => {
              if (!error) {
                this._newBlock(Object.assign({type: 'web3'}, result))
              }
            })
          }
        })
      }, 2)
    }
  }

  currentWeb3 () { // TODO this should maybe be put in app.js
    return this._appAPI.isVM() ? this._web3VMProvider : this._appAPI.web3()
  }

  /**
    * stop listening for incoming transactions. do not reset the recorded pool.
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  stopListening () {
    if (this.loopId) {
      clearInterval(this.loopId)
    }
    this.loopId = null
  }

  /**
    * try to resolve the contract name from the given @arg address
    *
    * @param {String} address - contract address to resolve
    * @return {String} - contract name
    */
  resolvedContract (address) {
    return this._resolvedContracts[address]
  }

  /**
    * try to resolve the transaction from the given @arg txHash
    *
    * @param {String} txHash - contract address to resolve
    * @return {String} - contract name
    */
  resolvedTransaction (txHash) {
    return this._resolvedTransactions[txHash]
  }

  _newBlock (block) {
    this.blocks.push(block)
    this._resolve(block, () => {
      this.event.trigger('newBlock', [block])
    })
  }

  _resolve (block, callback) {
    async.each(block.transactions, (tx, cb) => {
      this._resolveTx(tx, cb)
    }, () => {
      callback()
    })
  }

  _resolveTx (tx, cb) {
    var contracts = this._appAPI.contracts()
    if (!contracts) return cb()
    var contractName
    if (!tx.to) {
      // contract creation / resolve using the creation bytes code
      // if web3: we have to call getTransactionReceipt to get the created address
      // if VM: created address already included
      var code = tx.input
      contractName = this._tryResolveContract(code, contracts, 'bytecode')
      if (contractName) {
        this._resolveCreationAddress(tx, (error, address) => {
          if (error) return cb(error)
          this._resolvedContracts[address] = contractName
          this._resolveFunction(contractName, contracts, tx, true)
          if (this._resolvedTransactions[tx.hash]) {
            this._resolvedTransactions[tx.hash].contractAddress = address
          }
          return cb()
        })
        return
      }
      return cb()
    } else {
      // first check known contract, resolve against the `runtimeBytecode` if not known
      contractName = this._resolvedContracts[tx.to]
      if (!contractName) {
        this.currentWeb3().eth.getCode(tx.to, (error, code) => {
          if (error) return cb(error)
          if (code) {
            var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode')
            if (contractName) {
              this._resolvedContracts[tx.to] = contractName
              this._resolveFunction(contractName, contracts, tx, false)
              return cb()
            }
            return cb()
          }
          return cb()
        })
        return
      }
      if (contractName) {
        this._resolveFunction(contractName, contracts, tx, false)
        return cb()
      }
      return cb()
    }
  }

  _resolveCreationAddress (tx, cb) {
    this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
      if (!error) {
        cb(null, receipt.contractAddress)
      } else {
        cb(error)
      }
    })
  }

  _resolveFunction (contractName, compiledContracts, tx, isCtor) {
    var abi = JSON.parse(compiledContracts[contractName].interface)
    var inputData = tx.input.replace('0x', '')
    if (!isCtor) {
      for (var fn in compiledContracts[contractName].functionHashes) {
        if (compiledContracts[contractName].functionHashes[fn] === inputData.substring(0, 8)) {
          this._resolvedTransactions[tx.hash] = {
            to: tx.to,
            fn: fn,
            params: this._decodeInputParams(inputData.substring(8), getFunction(abi, fn))
          }
          return
        }
      }
      // fallback function
      this._resolvedTransactions[tx.hash] = {
        to: tx.to,
        fn: '(fallback)',
        params: null
      }
    } else {
      var bytecode = compiledContracts[contractName].bytecode
      var params = null
      if (bytecode && bytecode.length) {
        params = this._decodeInputParams(inputData.substring(bytecode.length), getConstructorInterface(abi))
      }
      this._resolvedTransactions[tx.hash] = {
        to: null,
        fn: '(constructor)',
        params: params
      }
    }
  }

  _tryResolveContract (codeToResolve, compiledContracts, type) {
    for (var k in compiledContracts) {
      if (codeUtil.compareByteCode(codeToResolve, '0x' + compiledContracts[k][type])) {
        return k
      }
    }
    return null
  }

  _decodeInputParams (data, abi) {
    data = ethJSUtil.toBuffer('0x' + data)
    var inputTypes = []
    for (var i = 0; i < abi.inputs.length; i++) {
      inputTypes.push(abi.inputs[i].type)
    }
    return ethJSABI.rawDecode(inputTypes, data)
  }
}


// those function will be duplicate after the merged of the compile and run tabs split
function getConstructorInterface (abi) {
  var funABI = { 'name': '', 'inputs': [], 'type': 'constructor', 'outputs': [] }
  for (var i = 0; i < abi.length; i++) {
    if (abi[i].type === 'constructor') {
      funABI.inputs = abi[i].inputs || []
      break
    }
  }

  return funABI
}

function getFunction (abi, fnName) {
  fnName = fnName.split('(')[0]
  for (var i = 0; i < abi.length; i++) {
    if (abi[i].name === fnName) {
      return abi[i]
    }
  }
  return null
}

module.exports = TxListener
{'fraction_non_alphanumeric': 0.12243633860977288, 'fraction_numerical': 0.003991741225051617, 'mean_word_length': 2.293517679057117, 'pattern_counts': {'":': 0, '<': 6, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5071942', 'n_tokens_mistral': 4377, 'n_tokens_neox': 4338, 'n_words': 1041}