/ lib / remote-importer / oxt-wrapper.js
oxt-wrapper.js
  1  /*!
  2   * lib/remote-importer/oxt-wrapper.js
  3   * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved.
  4   */
  5  
  6  
  7  import axios from 'axios'
  8  import Logger from '../logger.js'
  9  import network from '../bitcoin/network.js'
 10  import keysFile from '../../keys/index.js'
 11  import Wrapper from './wrapper.js'
 12  
 13  const keys = keysFile[network.key]
 14  
 15  /**
 16   * Wrapper for the oxt.me block explorer APIs
 17   */
 18  class OxtWrapper extends Wrapper {
 19  
 20      /**
 21       * Constructor
 22       * @constructor
 23       * @param {string} url
 24       */
 25      constructor(url) {
 26          super(url, keys.indexer.socks5Proxy)
 27      }
 28  
 29      /**
 30       * Send a GET request to the API
 31       * @param {string} route
 32       * @returns {Promise}
 33       */
 34      async _get(route) {
 35          const parameters = {
 36              url: `${this.base}${route}`,
 37              method: 'GET',
 38              responseType: 'json',
 39              timeout: 15000,
 40              headers: {
 41                  'User-Agent': 'Dojo'
 42              }
 43          }
 44  
 45          // Sets socks proxy agent if required
 46          if (keys.indexer.socks5Proxy != null) {
 47              parameters.httpAgent = this.socksProxyAgent
 48              parameters.httpsAgent = this.socksProxyAgent
 49          }
 50  
 51          const result = await axios(parameters)
 52          return result.data
 53      }
 54  
 55      /**
 56       * Retrieve information for a given address
 57       * @param {string} address - bitcoin address
 58       * @param {boolean} filterAddr - True if an upper bound should be used
 59       *     for #transactions associated to the address, False otherwise
 60       * @returns {Promise} returns an object
 61       *  { address: <bitcoin_address>, txids: <txids>, ntx: <total_nb_txs>}
 62       */
 63      async getAddress(address, filterAddr) {
 64          // Try to retrieve more txs than the 1000 managed by the backend
 65          const uri = `/addresses/${address}/txids?count=${keys.addrFilterThreshold + 1}`
 66          const result = await this._get(uri)
 67  
 68          const returnValue = {
 69              address: address,
 70              ntx: result.count,
 71              txids: []
 72          }
 73  
 74          // Check if we should filter this address
 75          if (filterAddr && returnValue.ntx > keys.addrFilterThreshold) {
 76              Logger.info(`Importer : Import of ${returnValue.address} rejected (too many transactions - ${returnValue.ntx})`)
 77              return returnValue
 78          }
 79  
 80          returnValue.txids = result.data.map(t => t.txid)
 81          return returnValue
 82      }
 83  
 84      /**
 85       * Retrieve information for a given list of addresses
 86       * @param {string} addresses - array of bitcoin addresses
 87       * @param {boolean} filterAddr - True if an upper bound should be used
 88       *     for #transactions associated to the address, False otherwise
 89       * @returns {Promise} returns an array of objects
 90       *  { address: <bitcoin_address>, txids: <txids>, ntx: <total_nb_txs>}
 91       */
 92      async getAddresses(addresses, filterAddr) {
 93          const returnValue = []
 94  
 95          // Send a batch request for all the addresses
 96          // For each address, try to retrieve more txs than the 1000 managed by the backend
 97          const stringAddr = addresses.join(',')
 98          const uri = `/addresses/multi/txids?count=${keys.addrFilterThreshold + 1}&addresses=${stringAddr}`
 99          const results = await this._get(uri)
100  
101          for (let r of results.data) {
102              const returnValueAddr = {
103                  address: r.address,
104                  ntx: r.txids.length,
105                  txids: []
106              }
107  
108              // Check if we should filter this address
109              if (filterAddr && returnValueAddr.ntx > keys.addrFilterThreshold) {
110                  Logger.info(`Importer : Import of ${returnValueAddr.address} rejected (too many transactions - ${returnValueAddr.ntx})`)
111              } else {
112                  returnValueAddr.txids = r.txids
113              }
114  
115              returnValue.push(returnValueAddr)
116          }
117  
118          return returnValue
119      }
120  
121      /**
122       * Retrieve the height of the chaintip for the remote source
123       * @returns {Promise} returns an object
124       *    {chainTipHeight: <chaintip_height>}
125       */
126      async getChainTipHeight() {
127          let chainTipHeight = null
128          const result = await this._get('/lastblock')
129          if (result != null && result.data.length === 1)
130              chainTipHeight = Number.parseInt(result.data[0].height, 10)
131          return { 'chainTipHeight': chainTipHeight }
132      }
133  
134  }
135  
136  export default OxtWrapper