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